mirror of
https://github.com/atdunbg/Nekosonic-Music.git
synced 2026-06-22 00:58:51 +08:00
refactor: 创建统一 API 封装层,前端不再直接调用 invoke
- 新增 src/api.ts,按职责分为 MusicApi/AudioApi/DeviceApi/DownloadApi/AppApi 五个命名空间 - 替换 15 个文件中所有 invoke 调用为 API 层方法 - 后端接口变更只需修改 api.ts 一处,便于后期迭代维护
This commit is contained in:
@ -59,7 +59,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { normalizeSong, type Song } from '../utils/song';
|
||||
import { formatDate } from '../utils/format';
|
||||
@ -79,7 +79,7 @@ async function fetchAlbum(id: number) {
|
||||
album.value = null;
|
||||
songs.value = [];
|
||||
try {
|
||||
const jsonStr: string = await invoke('album_detail', { id });
|
||||
const jsonStr: string = await MusicApi.albumDetail(id);
|
||||
const data = JSON.parse(jsonStr);
|
||||
album.value = data.album;
|
||||
songs.value = (data.songs || []).map(normalizeSong);
|
||||
|
||||
@ -83,7 +83,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue';
|
||||
import { useRoute, useRouter } from 'vue-router';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { formatPlayCount, formatDate } from '../utils/format';
|
||||
import { normalizeSong, type Song } from '../utils/song';
|
||||
@ -115,10 +115,10 @@ async function fetchArtist(id: number) {
|
||||
briefDesc.value = '';
|
||||
try {
|
||||
const [detailStr, songsStr, albumStr, descStr] = await Promise.all([
|
||||
invoke('artist_detail', { id }) as Promise<string>,
|
||||
invoke('artist_songs', { query: { id, order: 'hot', limit: 50, offset: 0 } }) as Promise<string>,
|
||||
invoke('artist_album', { id, limit: 30, offset: 0 }) as Promise<string>,
|
||||
invoke('artist_desc', { id }) as Promise<string>,
|
||||
MusicApi.artistDetail(id),
|
||||
MusicApi.artistSongs({ id, order: 'hot', limit: 50, offset: 0 }),
|
||||
MusicApi.artistAlbum(id, 30, 0),
|
||||
MusicApi.artistDesc(id),
|
||||
]);
|
||||
const detailData = JSON.parse(detailStr);
|
||||
artist.value = detailData.artist;
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onActivated, watch } from 'vue';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import SongListItem from '../components/SongListItem.vue';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { pageCacheGet, pageCacheSet, pageCacheInvalidate, pageCacheIsStale } from '../composables/usePageCache';
|
||||
@ -63,7 +63,7 @@ async function loadData() {
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const jsonStr: string = await invoke('recommend_songs');
|
||||
const jsonStr: string = await MusicApi.recommendSongs();
|
||||
const data = JSON.parse(jsonStr);
|
||||
songs.value = (data.data?.dailySongs || []).map(normalizeSong);
|
||||
pageCacheSet('dailySongs', songs.value);
|
||||
|
||||
@ -145,7 +145,7 @@ defineOptions({ name: 'DiscoverView' });
|
||||
|
||||
import { ref, computed, onMounted, onActivated, watch, nextTick } from 'vue';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import SongListItem from '../components/SongListItem.vue';
|
||||
import { normalizeSong, type Song } from '../utils/song';
|
||||
@ -231,7 +231,7 @@ function onInputChange() {
|
||||
}
|
||||
suggestTimer = setTimeout(async () => {
|
||||
try {
|
||||
const jsonStr: string = await invoke('search_suggest', { query: { keyword: keyword.value.trim() } });
|
||||
const jsonStr: string = await MusicApi.searchSuggest(keyword.value.trim());
|
||||
const data = JSON.parse(jsonStr);
|
||||
const all = data.result?.allMatch || [];
|
||||
suggestions.value = all.map((m: any) => m.keyword).slice(0, 8);
|
||||
@ -254,7 +254,7 @@ async function loadHotTags() {
|
||||
hotTags.value = cached;
|
||||
} else {
|
||||
try {
|
||||
const json = await invoke('get_hot_search');
|
||||
const json = await MusicApi.getHotSearch();
|
||||
const data = JSON.parse(json as string);
|
||||
hotTags.value = (data.data || []).slice(0, 12);
|
||||
pageCacheSet('discover_hotTags', hotTags.value);
|
||||
@ -317,8 +317,8 @@ async function fetchTabResults(type: number) {
|
||||
loading.value = true;
|
||||
cacheError.value = false;
|
||||
try {
|
||||
const jsonStr: string = await invoke('cloudsearch', {
|
||||
query: { keyword: lastSearchKeyword.value, searchType: type, limit: 30 }
|
||||
const jsonStr: string = await MusicApi.cloudsearch({
|
||||
keyword: lastSearchKeyword.value, searchType: type, limit: 30
|
||||
});
|
||||
const data = JSON.parse(jsonStr);
|
||||
const result = data.result || {};
|
||||
|
||||
@ -41,7 +41,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onActivated, watch } from 'vue';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import SongListItem from '../components/SongListItem.vue';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { useUserStore } from '../stores/user';
|
||||
@ -71,7 +71,7 @@ async function loadData() {
|
||||
}
|
||||
loading.value = true;
|
||||
try {
|
||||
const playlistJson: string = await invoke('user_playlist', { uid: userStore.user!.userId });
|
||||
const playlistJson: string = await MusicApi.userPlaylist(userStore.user!.userId);
|
||||
const playlistData = JSON.parse(playlistJson);
|
||||
const created = (playlistData.playlist || []).filter((p: any) => !p.subscribed);
|
||||
if (created.length === 0) {
|
||||
@ -79,7 +79,7 @@ async function loadData() {
|
||||
return;
|
||||
}
|
||||
const likePlaylistId = created[0].id;
|
||||
const trackJson: string = await invoke('playlist_track_all', { query: { id: likePlaylistId } });
|
||||
const trackJson: string = await MusicApi.playlistTrackAll(likePlaylistId);
|
||||
const trackData = JSON.parse(trackJson);
|
||||
songs.value = (trackData.songs || []).map(normalizeSong);
|
||||
pageCacheSet('favoriteSongs', songs.value);
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onActivated, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { useUserStore } from '../stores/user';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { pageCacheGet, pageCacheSet, pageCacheInvalidate, pageCacheIsStale } from '../composables/usePageCache';
|
||||
@ -169,7 +169,7 @@ async function loadData() {
|
||||
}
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
RANK_IDS.map(id => invoke('get_playlist_detail', { id }))
|
||||
RANK_IDS.map(id => MusicApi.getPlaylistDetail(id))
|
||||
);
|
||||
rankPlaylists.value = results
|
||||
.filter(r => r.status === 'fulfilled')
|
||||
@ -181,7 +181,7 @@ async function loadData() {
|
||||
|
||||
if (userStore.isLoggedIn) {
|
||||
try {
|
||||
const json = await invoke('recommend_resource');
|
||||
const json = await MusicApi.recommendResource();
|
||||
const data = JSON.parse(json as string);
|
||||
recPlaylists.value = data.recommend || [];
|
||||
} catch { /* 忽略 */ }
|
||||
|
||||
@ -76,7 +76,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onActivated, onBeforeUnmount, watch } from 'vue';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi, DownloadApi } from '../api';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { useDownload } from '../composables/useDownload';
|
||||
import { useSettingsStore } from '../stores/settings';
|
||||
@ -129,7 +129,7 @@ async function refresh() {
|
||||
loading.value = true;
|
||||
pageCacheInvalidate('localMusic');
|
||||
try {
|
||||
const list = await invoke<LocalSong[]>('list_local_songs', { downloadPath: settings.downloadPath || null });
|
||||
const list = await DownloadApi.listLocalSongs(settings.downloadPath || null);
|
||||
songs.value = list;
|
||||
pageCacheSet('localMusic', list);
|
||||
fetchMissingCovers();
|
||||
@ -145,7 +145,7 @@ async function fetchMissingCovers() {
|
||||
if (missing.length === 0) return;
|
||||
const ids = [...new Set(missing.map(s => s.id))];
|
||||
try {
|
||||
const jsonStr: string = await invoke('get_song_detail', { id: JSON.stringify(ids) });
|
||||
const jsonStr: string = await MusicApi.getSongDetail(JSON.stringify(ids));
|
||||
const data = JSON.parse(jsonStr);
|
||||
const detailMap = new Map<number, string>();
|
||||
for (const s of data.songs || []) {
|
||||
@ -194,7 +194,7 @@ function confirmDelete(song: LocalSong) {
|
||||
async function doDelete() {
|
||||
if (!deleteTarget.value) return;
|
||||
try {
|
||||
await invoke('delete_local_song', { query: { id: deleteTarget.value.id, filename: deleteTarget.value.filename, downloadPath: settings.downloadPath || null } });
|
||||
await DownloadApi.deleteLocalSong({ id: deleteTarget.value.id, filename: deleteTarget.value.filename, downloadPath: settings.downloadPath || null });
|
||||
songs.value = songs.value.filter(s => s.id !== deleteTarget.value!.id);
|
||||
download.localSongIds.delete(deleteTarget.value.id);
|
||||
showToast('已删除', 'success');
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useUserStore } from '../stores/user';
|
||||
import QRCode from 'qrcode';
|
||||
@ -52,7 +52,7 @@ async function refreshQr() {
|
||||
qrError.value = '';
|
||||
if (pollTimer) clearInterval(pollTimer);
|
||||
try {
|
||||
qrKey = await invoke('get_qr_key');
|
||||
qrKey = await MusicApi.getQrKey();
|
||||
if (!qrKey) {
|
||||
qrError.value = '未获取到登录密钥';
|
||||
qrLoading.value = false;
|
||||
@ -76,7 +76,7 @@ async function refreshQr() {
|
||||
function startPolling() {
|
||||
pollTimer = setInterval(async () => {
|
||||
try {
|
||||
const jsonStr: string = await invoke('check_qr_status', { query: { key: qrKey } });
|
||||
const jsonStr: string = await MusicApi.checkQrStatus(qrKey);
|
||||
const data = JSON.parse(jsonStr);
|
||||
const code = data.code;
|
||||
if (code === 800) {
|
||||
@ -104,7 +104,7 @@ function startPolling() {
|
||||
|
||||
async function fetchUserProfile() {
|
||||
try {
|
||||
const profileJson: string = await invoke('get_login_status');
|
||||
const profileJson: string = await MusicApi.getLoginStatus();
|
||||
const profile = JSON.parse(profileJson);
|
||||
if (profile.profile) {
|
||||
userStore.setUser({
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { MusicApi } from '../api';
|
||||
import { usePlayerStore } from '../stores/player';
|
||||
import { useUserStore } from '../stores/user';
|
||||
import { showToast } from '../composables/useToast';
|
||||
@ -98,7 +98,7 @@ async function fetchPlaylist(id: number) {
|
||||
playlist.value = null;
|
||||
songs.value = [];
|
||||
try {
|
||||
const jsonStr: string = await invoke('get_playlist_detail', { id });
|
||||
const jsonStr: string = await MusicApi.getPlaylistDetail(id);
|
||||
const data = JSON.parse(jsonStr);
|
||||
playlist.value = data.playlist;
|
||||
songs.value = (data.playlist.tracks || []).map(normalizeSong);
|
||||
@ -128,7 +128,7 @@ async function toggleSubscribe() {
|
||||
if (!playlist.value) return;
|
||||
const newSubscribed = !subscribed.value;
|
||||
try {
|
||||
await invoke('playlist_subscribe', { query: { id: Number(playlist.value.id), subscribe: newSubscribed } });
|
||||
await MusicApi.playlistSubscribe(Number(playlist.value.id), newSubscribed);
|
||||
subscribed.value = newSubscribed;
|
||||
showToast(subscribed.value ? '已收藏歌单' : '已取消收藏', 'success');
|
||||
} catch {
|
||||
|
||||
@ -258,7 +258,7 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
|
||||
import { useSettingsStore, qualityLabels, closeActionLabels, defaultShortcuts, themeLabels, themeColors, appearanceLabels, type CloseAction } from '../stores/settings';
|
||||
import { useToast } from '../composables/useToast';
|
||||
import { useUpdater } from '../composables/useUpdater';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { DeviceApi, DownloadApi } from '../api';
|
||||
import { getVersion } from '@tauri-apps/api/app';
|
||||
import { openUrl } from '@tauri-apps/plugin-opener';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
@ -287,7 +287,7 @@ const selectedDevice = computed({
|
||||
set: (val: string) => {
|
||||
const device = val === '' ? null : val;
|
||||
settings.setOutputDevice(device);
|
||||
invoke('set_output_device', { device }).then(() => {
|
||||
DeviceApi.setOutputDevice(device).then(() => {
|
||||
showToast(device ? `已切换到: ${device}` : '已切换到系统默认', 'success');
|
||||
}).catch((e) => {
|
||||
console.error('切换设备失败: ', e);
|
||||
@ -298,7 +298,7 @@ const selectedDevice = computed({
|
||||
|
||||
async function loadDevices() {
|
||||
try {
|
||||
devices.value = await invoke<string[]>('get_output_devices');
|
||||
devices.value = await DeviceApi.getOutputDevices();
|
||||
} catch (e) {
|
||||
console.error('获取设备失败: ', e);
|
||||
}
|
||||
@ -309,7 +309,7 @@ const defaultDownloadPath = ref('');
|
||||
onMounted(async () => {
|
||||
appVersion.value = await getVersion();
|
||||
try {
|
||||
defaultDownloadPath.value = await invoke<string>('get_default_download_path');
|
||||
defaultDownloadPath.value = await DownloadApi.getDefaultDownloadPath();
|
||||
} catch { /* 忽略 */ }
|
||||
loadDevices();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user