mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-05-17 02:07:29 +08:00
feat: 优化移动端界面设计以及歌词界面设计 添加播放模式选择
This commit is contained in:
@@ -114,6 +114,47 @@
|
||||
</div>
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
|
||||
<!-- 移动端设置 -->
|
||||
<n-tab-pane :name="'mobile'" :tab="t('settings.lyricSettings.tabs.mobile')">
|
||||
<div class="tab-content" v-if="isMobile">
|
||||
<div class="section-title">{{ t('settings.lyricSettings.mobileLayout') }}</div>
|
||||
<n-radio-group v-model:value="config.mobileLayout" name="mobileLayout" class="mb-4">
|
||||
<n-space>
|
||||
<n-radio value="default">{{ t('settings.lyricSettings.layoutOptions.default') }}</n-radio>
|
||||
<n-radio value="ios">{{ t('settings.lyricSettings.layoutOptions.ios') }}</n-radio>
|
||||
<n-radio value="android">{{ t('settings.lyricSettings.layoutOptions.android') }}</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
|
||||
<div class="section-title">{{ t('settings.lyricSettings.mobileCoverStyle') }}</div>
|
||||
<n-radio-group v-model:value="config.mobileCoverStyle" name="mobileCoverStyle" class="mb-4">
|
||||
<n-space>
|
||||
<n-radio value="record">{{ t('settings.lyricSettings.coverOptions.record') }}</n-radio>
|
||||
<n-radio value="square">{{ t('settings.lyricSettings.coverOptions.square') }}</n-radio>
|
||||
<n-radio value="full">{{ t('settings.lyricSettings.coverOptions.full') }}</n-radio>
|
||||
</n-space>
|
||||
</n-radio-group>
|
||||
|
||||
<div class="slider-item">
|
||||
<span>{{ t('settings.lyricSettings.lyricLines') }}</span>
|
||||
<n-slider
|
||||
v-model:value="config.mobileShowLyricLines"
|
||||
:step="1"
|
||||
:min="1"
|
||||
:max="5"
|
||||
:marks="{
|
||||
1: '1',
|
||||
3: '3',
|
||||
5: '5'
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mobile-unavailable">
|
||||
{{ t('settings.lyricSettings.mobileUnavailable') }}
|
||||
</div>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,6 +165,7 @@ import { onMounted, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { DEFAULT_LYRIC_CONFIG, LyricConfig } from '@/types/lyric';
|
||||
import { isMobile } from '@/utils';
|
||||
|
||||
const { t } = useI18n();
|
||||
const config = ref<LyricConfig>({ ...DEFAULT_LYRIC_CONFIG });
|
||||
@@ -253,4 +295,8 @@ defineExpose({
|
||||
color: var(--text-color-active) !important;
|
||||
@apply text-xs;
|
||||
}
|
||||
|
||||
.mobile-unavailable {
|
||||
@apply text-center py-4 text-gray-500 text-sm;
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,8 @@
|
||||
class="mobile-play-bar"
|
||||
:class="[
|
||||
setAnimationClass('animate__fadeInUp'),
|
||||
musicFullVisible ? 'play-bar-expanded' : 'play-bar-mini'
|
||||
musicFullVisible ? 'play-bar-expanded' : 'play-bar-mini',
|
||||
!shouldShowMobileMenu ? 'mobile-play-bar-no-menu' : ''
|
||||
]"
|
||||
:style="{
|
||||
color: musicFullVisible
|
||||
@@ -16,7 +17,7 @@
|
||||
}"
|
||||
>
|
||||
<!-- 完整模式 - 在musicFullVisible为true时显示 -->
|
||||
<template v-if="musicFullVisible">
|
||||
<template v-if="false">
|
||||
<!-- 顶部信息区域 -->
|
||||
<div class="music-info-header">
|
||||
<div class="music-info-main">
|
||||
@@ -61,31 +62,9 @@
|
||||
<div class="control-btn next" @click="handleNext">
|
||||
<i class="iconfont ri-skip-forward-fill"></i>
|
||||
</div>
|
||||
<n-popover
|
||||
trigger="click"
|
||||
:z-index="99999999"
|
||||
content-class="mobile-play-list"
|
||||
raw
|
||||
:show-arrow="false"
|
||||
placement="top"
|
||||
@update-show="scrollToPlayList"
|
||||
>
|
||||
<template #trigger>
|
||||
<div class="control-btn list">
|
||||
<i class="iconfont ri-menu-line"></i>
|
||||
</div>
|
||||
</template>
|
||||
<div class="mobile-play-list-container">
|
||||
<div class="mobile-play-list-back"></div>
|
||||
<n-virtual-list ref="playListRef" :item-size="56" item-resizable :items="playList">
|
||||
<template #default="{ item }">
|
||||
<div class="mobile-play-list-item">
|
||||
<song-item :key="item.id" :item="item" mini></song-item>
|
||||
</div>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
</div>
|
||||
</n-popover>
|
||||
<div class="control-btn list" @click="openPlayListDrawer">
|
||||
<i class="iconfont ri-menu-line"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 定时关闭按钮 -->
|
||||
@@ -93,7 +72,7 @@
|
||||
</template>
|
||||
|
||||
<!-- Mini模式 - 在musicFullVisible为false时显示 -->
|
||||
<div v-else class="mobile-mini-controls">
|
||||
<div v-if="!musicFullVisible" class="mobile-mini-controls">
|
||||
<!-- 歌曲信息 -->
|
||||
<div class="mini-song-info" @click="setMusicFull">
|
||||
<n-image
|
||||
@@ -103,12 +82,13 @@
|
||||
preview-disabled
|
||||
/>
|
||||
<div class="mini-song-text">
|
||||
<n-ellipsis class="mini-song-title" line-clamp="1">
|
||||
{{ playMusic.name }}
|
||||
</n-ellipsis>
|
||||
<n-ellipsis class="mini-song-artist" line-clamp="1">
|
||||
<span v-for="(artists, artistsindex) in artistList" :key="artistsindex">
|
||||
{{ artists.name }}{{ artistsindex < artistList.length - 1 ? ' / ' : '' }}
|
||||
<n-ellipsis line-clamp="1">
|
||||
<span class="mini-song-title">{{ playMusic.name }}</span>
|
||||
<span class="mx-2 text-gray-500 dark:text-gray-400">-</span>
|
||||
<span class="mini-song-artist">
|
||||
<span v-for="(artists, artistsindex) in artistList" :key="artistsindex">
|
||||
{{ artists.name }}{{ artistsindex < artistList.length - 1 ? ' / ' : '' }}
|
||||
</span>
|
||||
</span>
|
||||
</n-ellipsis>
|
||||
</div>
|
||||
@@ -119,34 +99,12 @@
|
||||
<div class="mini-control-btn play" @click="playMusicEvent">
|
||||
<i class="iconfont icon" :class="play ? 'icon-stop' : 'icon-play'"></i>
|
||||
</div>
|
||||
<n-popover
|
||||
trigger="click"
|
||||
:z-index="99999999"
|
||||
content-class="mobile-play-list"
|
||||
raw
|
||||
:show-arrow="false"
|
||||
placement="top"
|
||||
@update-show="scrollToPlayList"
|
||||
>
|
||||
<template #trigger>
|
||||
<i class="iconfont icon-list mini-list-icon"></i>
|
||||
</template>
|
||||
<div class="mobile-play-list-container">
|
||||
<div class="mobile-play-list-back"></div>
|
||||
<n-virtual-list ref="playListRef" :item-size="56" item-resizable :items="playList">
|
||||
<template #default="{ item }">
|
||||
<div class="mobile-play-list-item">
|
||||
<song-item :key="item.id" :item="item" mini></song-item>
|
||||
</div>
|
||||
</template>
|
||||
</n-virtual-list>
|
||||
</div>
|
||||
</n-popover>
|
||||
<i class="iconfont icon-list mini-list-icon" @click="openPlayListDrawer"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全屏播放器 -->
|
||||
<music-full ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
||||
<music-full-wrapper ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -154,21 +112,19 @@
|
||||
import { useThrottleFn } from '@vueuse/core';
|
||||
import { computed, ref, watch } from 'vue';
|
||||
|
||||
import SongItem from '@/components/common/SongItem.vue';
|
||||
import { allTime, artistList, nowTime, playMusic, sound, textColors } from '@/hooks/MusicHook';
|
||||
import MusicFull from '@/layout/components/MusicFull.vue';
|
||||
import MusicFullWrapper from '@/layout/components/MusicFullWrapper.vue';
|
||||
import { usePlayerStore } from '@/store/modules/player';
|
||||
import { useSettingsStore } from '@/store/modules/settings';
|
||||
import type { SongResult } from '@/type/music';
|
||||
import { getImgUrl, secondToMinute, setAnimationClass } from '@/utils';
|
||||
|
||||
const shouldShowMobileMenu = inject('shouldShowMobileMenu');
|
||||
|
||||
const playerStore = usePlayerStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
|
||||
// 是否播放
|
||||
const play = computed(() => playerStore.isPlay);
|
||||
// 播放列表
|
||||
const playList = computed(() => playerStore.playList as SongResult[]);
|
||||
// 背景颜色
|
||||
const background = ref('#000');
|
||||
|
||||
@@ -206,14 +162,9 @@ const setMusicFull = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 播放列表引用
|
||||
const playListRef = ref<any>(null);
|
||||
|
||||
const scrollToPlayList = (val: boolean) => {
|
||||
if (!val) return;
|
||||
setTimeout(() => {
|
||||
playListRef.value?.scrollTo({ top: playerStore.playListIndex * 56 });
|
||||
}, 50);
|
||||
// 打开播放列表抽屉
|
||||
const openPlayListDrawer = () => {
|
||||
playerStore.setPlayListDrawerVisible(true);
|
||||
};
|
||||
|
||||
// 收藏功能
|
||||
@@ -251,11 +202,15 @@ watch(
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mobile-play-bar {
|
||||
@apply fixed bottom-[56px] left-0 w-full flex flex-col shadow-lg;
|
||||
@apply fixed bottom-[56px] left-0 w-full flex flex-col;
|
||||
z-index: 10000;
|
||||
animation-duration: 0.3s !important;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.mobile-play-bar-no-menu {
|
||||
@apply bottom-[10px];
|
||||
}
|
||||
|
||||
&.play-bar-expanded {
|
||||
@apply bg-transparent;
|
||||
height: auto; /* 自动适应内容高度 */
|
||||
@@ -285,7 +240,7 @@ watch(
|
||||
}
|
||||
|
||||
&.play-bar-mini {
|
||||
@apply h-14 py-0 bg-light dark:bg-dark;
|
||||
@apply h-14 py-0;
|
||||
}
|
||||
|
||||
// 顶部信息区域
|
||||
@@ -423,13 +378,13 @@ watch(
|
||||
|
||||
// Mini模式样式
|
||||
.mobile-mini-controls {
|
||||
@apply flex items-center justify-between px-4 h-14;
|
||||
@apply flex items-center justify-between pr-4 mx-3 h-12 rounded-full bg-light-100 dark:bg-dark-100 shadow-lg;
|
||||
|
||||
.mini-song-info {
|
||||
@apply flex items-center flex-1 min-w-0 cursor-pointer;
|
||||
|
||||
.mini-song-cover {
|
||||
@apply w-8 h-8 rounded-md;
|
||||
@apply w-12 h-12 rounded-full border-8 border-dark-300 dark:border-light-300;
|
||||
}
|
||||
|
||||
.mini-song-text {
|
||||
@@ -440,7 +395,7 @@ watch(
|
||||
}
|
||||
|
||||
.mini-song-artist {
|
||||
@apply text-xs text-gray-500 dark:text-gray-400 mt-0.5;
|
||||
@apply text-xs text-gray-500 dark:text-gray-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,8 +148,8 @@
|
||||
{{ t('player.playBar.playList') }}
|
||||
</n-tooltip>
|
||||
</div>
|
||||
<!-- 播放音乐 -->
|
||||
<music-full ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
||||
<!-- 全屏播放器 -->
|
||||
<music-full-wrapper ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -169,7 +169,7 @@ import {
|
||||
textColors
|
||||
} from '@/hooks/MusicHook';
|
||||
import { useArtist } from '@/hooks/useArtist';
|
||||
import MusicFull from '@/layout/components/MusicFull.vue';
|
||||
import MusicFullWrapper from '@/layout/components/MusicFullWrapper.vue';
|
||||
import { audioService } from '@/services/audioService';
|
||||
import {
|
||||
isBilibiliIdMatch,
|
||||
|
||||
@@ -117,6 +117,10 @@ const handleClearPlaylist = () => {
|
||||
message.info(t('player.playList.alreadyEmpty'));
|
||||
return;
|
||||
}
|
||||
|
||||
if(isMobile.value){
|
||||
closePanel();
|
||||
}
|
||||
|
||||
dialog.warning({
|
||||
title: t('player.playList.clearConfirmTitle'),
|
||||
@@ -254,17 +258,18 @@ const handleDeleteSong = (song: SongResult) => {
|
||||
// 移动端适配
|
||||
@media (max-width: 768px) {
|
||||
.playlist-panel {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
height: 80vh;
|
||||
top: auto;
|
||||
bottom: 56px; // 移动端底部留出导航栏高度
|
||||
border-radius: 16px 16px 0 0;
|
||||
bottom: 0; // 移动端底部留出导航栏高度
|
||||
border-radius: 30px 30px 0 0;
|
||||
border-left: none;
|
||||
border-top: 1px solid theme('colors.gray.200');
|
||||
box-shadow: 0 -5px 20px rgba(0, 0, 0, 0.1);
|
||||
|
||||
&-header {
|
||||
@apply text-center relative;
|
||||
@apply text-center relative px-4;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
@@ -280,7 +285,11 @@ const handleDeleteSong = (song: SongResult) => {
|
||||
}
|
||||
|
||||
&-content {
|
||||
height: calc(60vh - 60px);
|
||||
height: calc(80vh - 60px);
|
||||
@apply px-4;
|
||||
.delete-btn{
|
||||
@apply visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import { useMessage } from 'naive-ui';
|
||||
|
||||
import { getSongUrl } from '@/store/modules/player';
|
||||
import type { SongResult } from '@/type/music';
|
||||
import { isElectron } from '@/utils';
|
||||
|
||||
const ipcRenderer = isElectron ? window.electron.ipcRenderer : null;
|
||||
|
||||
// 全局下载管理(闭包模式)
|
||||
const createDownloadManager = () => {
|
||||
@@ -58,11 +61,11 @@ const createDownloadManager = () => {
|
||||
|
||||
// 移除可能存在的旧监听器
|
||||
if (completeListener) {
|
||||
window.electron.ipcRenderer.removeListener('music-download-complete', completeListener);
|
||||
ipcRenderer?.removeListener('music-download-complete', completeListener);
|
||||
}
|
||||
|
||||
if (errorListener) {
|
||||
window.electron.ipcRenderer.removeListener('music-download-error', errorListener);
|
||||
ipcRenderer?.removeListener('music-download-error', errorListener);
|
||||
}
|
||||
|
||||
// 创建新的监听器
|
||||
@@ -99,8 +102,8 @@ const createDownloadManager = () => {
|
||||
};
|
||||
|
||||
// 添加监听器
|
||||
window.electron.ipcRenderer.on('music-download-complete', completeListener);
|
||||
window.electron.ipcRenderer.on('music-download-error', errorListener);
|
||||
ipcRenderer?.on('music-download-complete', completeListener);
|
||||
ipcRenderer?.on('music-download-error', errorListener);
|
||||
|
||||
isInitialized = true;
|
||||
},
|
||||
@@ -110,12 +113,12 @@ const createDownloadManager = () => {
|
||||
if (!isInitialized) return;
|
||||
|
||||
if (completeListener) {
|
||||
window.electron.ipcRenderer.removeListener('music-download-complete', completeListener);
|
||||
ipcRenderer?.removeListener('music-download-complete', completeListener);
|
||||
completeListener = null;
|
||||
}
|
||||
|
||||
if (errorListener) {
|
||||
window.electron.ipcRenderer.removeListener('music-download-error', errorListener);
|
||||
ipcRenderer?.removeListener('music-download-error', errorListener);
|
||||
errorListener = null;
|
||||
}
|
||||
|
||||
@@ -181,7 +184,7 @@ export const useDownload = () => {
|
||||
songData.ar = songData.ar || songData.song?.artists;
|
||||
|
||||
// 发送下载请求
|
||||
window.electron.ipcRenderer.send('download-music', {
|
||||
ipcRenderer?.send('download-music', {
|
||||
url: typeof musicUrl === 'string' ? musicUrl : musicUrl.url,
|
||||
filename,
|
||||
songInfo: {
|
||||
@@ -277,7 +280,7 @@ export const useDownload = () => {
|
||||
downloadTime: Date.now()
|
||||
};
|
||||
|
||||
window.electron.ipcRenderer.send('download-music', {
|
||||
ipcRenderer?.send('download-music', {
|
||||
url,
|
||||
filename,
|
||||
songInfo,
|
||||
|
||||
@@ -53,9 +53,9 @@ export function useSongItem(props: {
|
||||
const handleImageLoad = async (imageElement: HTMLImageElement) => {
|
||||
if (!imageElement) return;
|
||||
|
||||
const { backgroundColor } = await getImageBackground(imageElement);
|
||||
// eslint-disable-next-line vue/no-mutating-props
|
||||
const { backgroundColor, primaryColor } = await getImageBackground(imageElement);
|
||||
props.item.backgroundColor = backgroundColor;
|
||||
props.item.primaryColor = primaryColor;
|
||||
};
|
||||
|
||||
// 播放音乐
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<!-- 搜索栏 -->
|
||||
<search-bar />
|
||||
<!-- 主页面路由 -->
|
||||
<div class="main-content" :native-scrollbar="false">
|
||||
<div class="main-content" :native-scrollbar="false" :class="{'mobile-content': !shouldShowMobileMenu}">
|
||||
<router-view
|
||||
v-slot="{ Component }"
|
||||
class="main-page"
|
||||
@@ -21,7 +21,7 @@
|
||||
</router-view>
|
||||
</div>
|
||||
<play-bottom />
|
||||
<app-menu v-if="isMobile && !playerStore.musicFull" class="menu" :menus="menus" />
|
||||
<app-menu v-if="shouldShowMobileMenu" class="menu" :menus="menus" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- 底部音乐播放 -->
|
||||
@@ -103,6 +103,16 @@ const isPlay = computed(() => playerStore.playMusic && playerStore.playMusic.id)
|
||||
const { menus } = menuStore;
|
||||
const route = useRoute();
|
||||
|
||||
// 判断当前路由是否应该在移动端显示AppMenu
|
||||
const shouldShowMobileMenu = computed(() => {
|
||||
// 过滤出在menus中定义的路径
|
||||
const menuPaths = menus.map((item: any) => item.path);
|
||||
// 检查当前路由路径是否在menus中
|
||||
return menuPaths.includes(route.path) && isMobile.value && !playerStore.musicFull;
|
||||
});
|
||||
|
||||
provide('shouldShowMobileMenu', shouldShowMobileMenu);
|
||||
|
||||
onMounted(() => {
|
||||
settingsStore.initializeSettings();
|
||||
settingsStore.initializeTheme();
|
||||
@@ -156,7 +166,10 @@ provide('openPlaylistDrawer', openPlaylistDrawer);
|
||||
overflow: auto;
|
||||
display: block;
|
||||
flex: none;
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
.mobile-content {
|
||||
height: calc(100vh - 75px);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useRoute } from 'vue-router';
|
||||
import { ref, watch } from 'vue';
|
||||
|
||||
import icon from '@/assets/icon.png';
|
||||
|
||||
@@ -115,7 +116,7 @@ const isText = ref(false);
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 99999;
|
||||
@apply bg-light dark:bg-black border-t border-gray-200 dark:border-gray-700;
|
||||
@apply bg-light dark:bg-black border-none border-gray-200 dark:border-gray-700;
|
||||
|
||||
&-header {
|
||||
display: none;
|
||||
@@ -127,9 +128,16 @@ const isText = ref(false);
|
||||
|
||||
&-item {
|
||||
&-link {
|
||||
@apply my-2 w-auto;
|
||||
@apply my-2 w-auto px-2;
|
||||
width: auto !important;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-expanded {
|
||||
@apply w-full;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<component :is="componentToUse" v-bind="$attrs" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { isMobile } from '@/utils';
|
||||
import MusicFull from '@/layout/components/MusicFull.vue';
|
||||
import MusicFullMobile from '@/components/lyric/MusicFullMobile.vue';
|
||||
|
||||
// 根据当前设备类型选择需要显示的组件
|
||||
const componentToUse = computed(() => {
|
||||
return isMobile.value ? MusicFullMobile : MusicFull;
|
||||
});
|
||||
</script>
|
||||
@@ -20,10 +20,11 @@ const getSettingsStore = () => {
|
||||
const loginRouter = {
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
mate: {
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
title: '登录',
|
||||
icon: 'icon-Home'
|
||||
icon: 'icon-Home',
|
||||
back: true
|
||||
},
|
||||
component: () => import('@/views/login/index.vue')
|
||||
};
|
||||
@@ -31,7 +32,7 @@ const loginRouter = {
|
||||
const setRouter = {
|
||||
path: '/set',
|
||||
name: 'set',
|
||||
mate: {
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
title: '设置',
|
||||
icon: 'icon-Home'
|
||||
|
||||
@@ -10,6 +10,10 @@ export interface LyricConfig {
|
||||
pureModeEnabled: boolean;
|
||||
hideMiniPlayBar: boolean;
|
||||
hideLyrics: boolean;
|
||||
// 移动端配置
|
||||
mobileLayout: 'default' | 'ios' | 'android';
|
||||
mobileCoverStyle: 'record' | 'square' | 'full';
|
||||
mobileShowLyricLines: number;
|
||||
}
|
||||
|
||||
export const DEFAULT_LYRIC_CONFIG: LyricConfig = {
|
||||
@@ -23,5 +27,9 @@ export const DEFAULT_LYRIC_CONFIG: LyricConfig = {
|
||||
hidePlayBar: false,
|
||||
hideMiniPlayBar: true,
|
||||
pureModeEnabled: false,
|
||||
hideLyrics: false
|
||||
hideLyrics: false,
|
||||
// 移动端默认配置
|
||||
mobileLayout: 'ios',
|
||||
mobileCoverStyle: 'full',
|
||||
mobileShowLyricLines: 3
|
||||
};
|
||||
|
||||
@@ -115,6 +115,7 @@
|
||||
:compact="isCompactLayout"
|
||||
:item="formatSong(item)"
|
||||
@play="handlePlay"
|
||||
:style="{paddingBottom: index === filteredSongs.length - 1 ? '100px' : '0'}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -697,7 +698,7 @@ const handleVirtualScroll = (e: any) => {
|
||||
}
|
||||
|
||||
.albums-grid {
|
||||
@apply grid gap-6 grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-6;
|
||||
@apply grid gap-6 grid-cols-2 sm:grid-cols-3 md:grid-cols-5 lg:grid-cols-6 pb-40;
|
||||
}
|
||||
|
||||
.loading-more {
|
||||
|
||||
@@ -539,7 +539,7 @@ const handleBatchDownload = async () => {
|
||||
|
||||
.mobile {
|
||||
.favorite-page {
|
||||
@apply p-4;
|
||||
@apply p-4 m-0;
|
||||
|
||||
.favorite-header {
|
||||
@apply mb-4;
|
||||
|
||||
@@ -146,7 +146,7 @@ const loginPhone = async () => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.login-page {
|
||||
@apply flex flex-col items-center justify-center p-20 pt-20;
|
||||
@apply flex flex-col items-center justify-center pt-20;
|
||||
@apply bg-light dark:bg-black;
|
||||
}
|
||||
|
||||
@@ -216,4 +216,10 @@ const loginPhone = async () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mobile {
|
||||
.login-page {
|
||||
@apply pt-0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
<n-virtual-list
|
||||
ref="songListRef"
|
||||
class="song-virtual-list"
|
||||
style="height: calc(80vh - 60px)"
|
||||
style="max-height: calc(100vh - 130px);"
|
||||
:items="filteredSongs"
|
||||
:item-size="isCompactLayout ? 50 : 70"
|
||||
item-resizable
|
||||
@@ -179,6 +179,7 @@
|
||||
@play="handlePlay"
|
||||
@remove-song="handleRemoveSong"
|
||||
@select="(id, selected) => handleSelect(id, selected)"
|
||||
:style="{paddingBottom: index === filteredSongs.length - 1 ? '100px' : '0'}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -90,6 +90,10 @@
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 未登录时显示登录组件 -->
|
||||
<div v-if="!isLoggedIn && isMobile" class="login-container" :class="setAnimationClass('animate__fadeIn')">
|
||||
<login-component @login-success="handleLoginSuccess" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -109,6 +113,7 @@ import { useUserStore } from '@/store/modules/user';
|
||||
import type { Playlist } from '@/type/listDetail';
|
||||
import type { IUserDetail } from '@/type/user';
|
||||
import { getImgUrl, isElectron, isMobile, setAnimationClass, setAnimationDelay } from '@/utils';
|
||||
import LoginComponent from '@/views/login/index.vue';
|
||||
|
||||
defineOptions({
|
||||
name: 'User'
|
||||
@@ -143,7 +148,7 @@ const checkLoginStatus = () => {
|
||||
const userData = localStorage.getItem('user');
|
||||
|
||||
if (!token || !userData) {
|
||||
router.push('/login');
|
||||
!isMobile.value && router.push('/login');
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -270,6 +275,14 @@ const showFollowList = () => {
|
||||
// if (!user.value) return;
|
||||
// router.push('/user/followers');
|
||||
// };
|
||||
|
||||
const handleLoginSuccess = () => {
|
||||
// 处理登录成功后的逻辑
|
||||
checkLoginStatus();
|
||||
loadData();
|
||||
};
|
||||
|
||||
const isLoggedIn = computed(() => userStore.user);
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -398,5 +411,9 @@ const showFollowList = () => {
|
||||
.user-page {
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
.login-container {
|
||||
@apply flex justify-center items-center h-full w-full;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user