2023-11-23 18:28:53 +08:00
|
|
|
<template>
|
|
|
|
|
<div class="cloud">
|
|
|
|
|
<n-h1 class="title">我的云盘</n-h1>
|
|
|
|
|
<!-- 基础状态 -->
|
|
|
|
|
<n-progress
|
|
|
|
|
:percentage="100 / (userCloudSpace[1] / userCloudSpace[0])"
|
|
|
|
|
class="status"
|
|
|
|
|
type="line"
|
|
|
|
|
>
|
|
|
|
|
<div class="tip">
|
|
|
|
|
<n-text class="space" depth="3">
|
|
|
|
|
云盘容量 {{ userCloudSpace[0] ?? 0 }}GB / {{ userCloudSpace[1] ?? 0 }}GB
|
|
|
|
|
</n-text>
|
|
|
|
|
<n-text class="buy" @click="goBuy"> 扩容 </n-text>
|
|
|
|
|
</div>
|
|
|
|
|
</n-progress>
|
|
|
|
|
<!-- 功能区 -->
|
|
|
|
|
<n-space class="menu" justify="space-between">
|
|
|
|
|
<n-space class="left">
|
|
|
|
|
<n-button type="primary" class="play" circle strong secondary @click="playAllSongs">
|
|
|
|
|
<template #icon>
|
|
|
|
|
<n-icon size="32">
|
|
|
|
|
<SvgIcon icon="play-arrow-rounded" />
|
|
|
|
|
</n-icon>
|
|
|
|
|
</template>
|
|
|
|
|
</n-button>
|
|
|
|
|
<n-button size="large" round strong secondary @click="upCloudSongRef?.openUpSongModal()">
|
|
|
|
|
<template #icon>
|
|
|
|
|
<n-icon>
|
|
|
|
|
<SvgIcon icon="cloud-arrow-up" />
|
|
|
|
|
</n-icon>
|
|
|
|
|
</template>
|
|
|
|
|
上传歌曲
|
|
|
|
|
</n-button>
|
|
|
|
|
<!-- 歌曲上传弹窗 -->
|
|
|
|
|
<UpCloudSong ref="upCloudSongRef" @getUserCloudData="getUserCloudData" />
|
|
|
|
|
</n-space>
|
|
|
|
|
<n-space class="right">
|
|
|
|
|
<!-- 模糊搜索 -->
|
|
|
|
|
<Transition name="fade" mode="out-in">
|
|
|
|
|
<n-input
|
|
|
|
|
v-if="userCloudData?.length"
|
|
|
|
|
v-model:value="searchValue"
|
|
|
|
|
:input-props="{ autoComplete: false }"
|
|
|
|
|
class="search"
|
|
|
|
|
placeholder="模糊搜索"
|
|
|
|
|
clearable
|
|
|
|
|
@input="localSearch"
|
|
|
|
|
>
|
|
|
|
|
<template #prefix>
|
|
|
|
|
<n-icon size="18">
|
|
|
|
|
<SvgIcon icon="search-rounded" />
|
|
|
|
|
</n-icon>
|
|
|
|
|
</template>
|
|
|
|
|
</n-input>
|
|
|
|
|
</Transition>
|
|
|
|
|
</n-space>
|
|
|
|
|
</n-space>
|
|
|
|
|
<!-- 列表 -->
|
|
|
|
|
<Transition name="fade" mode="out-in">
|
2023-12-21 15:56:20 +08:00
|
|
|
<div v-if="userCloudData !== 'empty'" class="list">
|
|
|
|
|
<Transition name="fade" mode="out-in">
|
|
|
|
|
<SongList v-if="!searchValue" :data="userCloudData" :showPrivilege="false" />
|
|
|
|
|
<SongList v-else-if="searchData?.length" :data="searchData" :showPrivilege="false" />
|
|
|
|
|
<n-empty
|
|
|
|
|
v-else
|
|
|
|
|
:description="`搜不到关于 ${searchValue} 的任何歌曲呀`"
|
|
|
|
|
style="margin-top: 60px"
|
|
|
|
|
size="large"
|
|
|
|
|
>
|
|
|
|
|
<template #icon>
|
|
|
|
|
<n-icon>
|
|
|
|
|
<SvgIcon icon="search-off" />
|
|
|
|
|
</n-icon>
|
|
|
|
|
</template>
|
|
|
|
|
</n-empty>
|
|
|
|
|
</Transition>
|
|
|
|
|
</div>
|
|
|
|
|
<n-empty v-else class="empty" description="你还没播放任何歌曲" />
|
2023-11-23 18:28:53 +08:00
|
|
|
</Transition>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script setup>
|
|
|
|
|
import { storeToRefs } from "pinia";
|
|
|
|
|
import { musicData, indexedDBData } from "@/stores";
|
2023-11-24 10:25:50 +08:00
|
|
|
import { getUserCloud } from "@/api/cloud";
|
|
|
|
|
import { fuzzySearch } from "@/utils/helper";
|
|
|
|
|
import { fadePlayOrPause, initPlayer } from "@/utils/Player";
|
|
|
|
|
import debounce from "@/utils/debounce";
|
|
|
|
|
import formatData from "@/utils/formatData";
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
|
|
|
const music = musicData();
|
|
|
|
|
const indexedDB = indexedDBData();
|
2023-12-19 18:08:46 +08:00
|
|
|
const { playList, playIndex, playSongData, playHeartbeatMode, playMode } = storeToRefs(music);
|
2023-11-23 18:28:53 +08:00
|
|
|
|
|
|
|
|
// 云盘数据
|
|
|
|
|
const userCloudSpace = ref([]);
|
|
|
|
|
const userCloudData = ref([]);
|
|
|
|
|
const upCloudSongRef = ref(null);
|
|
|
|
|
|
|
|
|
|
// 模糊搜索数据
|
|
|
|
|
const searchValue = ref(null);
|
|
|
|
|
const searchData = ref([]);
|
|
|
|
|
|
|
|
|
|
// 获取用户云盘缓存数据
|
|
|
|
|
const getUserCloudDataList = async () => {
|
|
|
|
|
await indexedDB.getfilesDB("userCloudList").then((res) => {
|
|
|
|
|
userCloudData.value = res;
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 获取用户云盘列表
|
|
|
|
|
const getUserCloudData = async (isOnce = false) => {
|
|
|
|
|
try {
|
|
|
|
|
// 初始化数据
|
|
|
|
|
let offset = 0;
|
|
|
|
|
let totalCount = null;
|
|
|
|
|
let resultArr = [];
|
|
|
|
|
userCloudData.value = [];
|
|
|
|
|
// 获取数据
|
|
|
|
|
while (totalCount === null || offset < totalCount) {
|
|
|
|
|
const res = await getUserCloud(100, offset);
|
|
|
|
|
resultArr.push(formatData(res.data, "song"));
|
|
|
|
|
offset += 100;
|
|
|
|
|
// 歌曲总数
|
|
|
|
|
totalCount = res.count;
|
|
|
|
|
// 云盘空间
|
|
|
|
|
userCloudSpace.value = [
|
|
|
|
|
(res.size / Math.pow(1024, 3)).toFixed(2),
|
|
|
|
|
(res.maxSize / Math.pow(1024, 3)).toFixed(0),
|
|
|
|
|
];
|
2023-12-21 15:56:20 +08:00
|
|
|
if (res.count === 0) {
|
|
|
|
|
userCloudData.value = "empty";
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-11-23 18:28:53 +08:00
|
|
|
if (isOnce) break;
|
|
|
|
|
}
|
|
|
|
|
// 展平并赋值
|
|
|
|
|
const resultArrFlat = resultArr.flat();
|
|
|
|
|
userCloudData.value = resultArrFlat;
|
|
|
|
|
// 更新本地歌曲
|
|
|
|
|
await indexedDB.setfilesDB("userCloudList", resultArrFlat.slice());
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error("云盘数据加载失败:", error);
|
|
|
|
|
$message.error("云盘数据加载失败");
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2023-12-01 15:29:14 +08:00
|
|
|
// 歌曲模糊搜索
|
2023-11-23 18:28:53 +08:00
|
|
|
const localSearch = debounce((val) => {
|
|
|
|
|
const searchValue = val?.trim();
|
|
|
|
|
// 是否为空
|
|
|
|
|
if (!searchValue || searchValue === "") {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
// 返回结果
|
|
|
|
|
const result = fuzzySearch(searchValue, userCloudData.value);
|
|
|
|
|
searchData.value = result;
|
|
|
|
|
}, 300);
|
|
|
|
|
|
|
|
|
|
// 播放歌单全部歌曲
|
|
|
|
|
const playAllSongs = async () => {
|
|
|
|
|
if (!userCloudData.value || !Object.keys(userCloudData.value).length) return false;
|
|
|
|
|
// 关闭心动模式
|
|
|
|
|
playHeartbeatMode.value = false;
|
2023-12-19 18:08:46 +08:00
|
|
|
// 更改模式和歌单
|
|
|
|
|
playMode.value = "normal";
|
|
|
|
|
playList.value = userCloudData.value.slice();
|
2023-11-23 18:28:53 +08:00
|
|
|
// 是否处于歌单内
|
|
|
|
|
const songId = playSongData.value?.id;
|
2023-12-19 18:08:46 +08:00
|
|
|
const existingIndex = userCloudData.value.findIndex((song) => song.id === songId);
|
2023-11-23 18:28:53 +08:00
|
|
|
// 若不处于
|
2023-12-19 18:08:46 +08:00
|
|
|
if (existingIndex === -1 || !songId) {
|
2023-11-23 18:28:53 +08:00
|
|
|
playSongData.value = userCloudData.value[0];
|
|
|
|
|
playIndex.value = 0;
|
|
|
|
|
// 初始化播放器
|
2023-12-21 15:56:20 +08:00
|
|
|
await initPlayer(true);
|
2023-11-23 18:28:53 +08:00
|
|
|
} else {
|
2023-12-19 18:08:46 +08:00
|
|
|
playSongData.value = userCloudData.value[existingIndex];
|
|
|
|
|
playIndex.value = existingIndex;
|
2023-12-14 15:10:23 +08:00
|
|
|
fadePlayOrPause();
|
2023-11-23 18:28:53 +08:00
|
|
|
}
|
|
|
|
|
$message.info("已开始播放", { showIcon: false });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 云盘扩容
|
|
|
|
|
const goBuy = () => {
|
|
|
|
|
window.open("https://music.163.com/#/store/product/detail?id=34001");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
onBeforeMount(() => {
|
|
|
|
|
getUserCloudDataList();
|
|
|
|
|
getUserCloudData();
|
|
|
|
|
});
|
2023-12-07 13:34:51 +08:00
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
|
window.$refreshCloudList = getUserCloudDataList;
|
|
|
|
|
});
|
2023-11-23 18:28:53 +08:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
.cloud {
|
|
|
|
|
.title {
|
|
|
|
|
margin: 20px 0;
|
|
|
|
|
font-size: 36px;
|
|
|
|
|
font-weight: bold;
|
|
|
|
|
}
|
|
|
|
|
.status {
|
|
|
|
|
width: 340px;
|
|
|
|
|
--n-fill-color: var(--main-color);
|
|
|
|
|
.tip {
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: row;
|
|
|
|
|
align-items: center;
|
|
|
|
|
.buy {
|
|
|
|
|
margin-left: 8px;
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
&::after {
|
|
|
|
|
content: ">";
|
|
|
|
|
margin-left: 2px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.menu {
|
|
|
|
|
align-items: center;
|
|
|
|
|
margin: 26px 0;
|
|
|
|
|
.left {
|
|
|
|
|
align-items: center;
|
|
|
|
|
.play {
|
|
|
|
|
--n-width: 46px;
|
|
|
|
|
--n-height: 46px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
.right {
|
|
|
|
|
.search {
|
|
|
|
|
height: 40px;
|
|
|
|
|
width: 130px;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
border-radius: 40px;
|
|
|
|
|
transition:
|
|
|
|
|
width 0.3s,
|
|
|
|
|
background-color 0.3s;
|
|
|
|
|
&.n-input--focus {
|
|
|
|
|
width: 200px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|