mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-03 14:20:50 +08:00
feat: 用户页面添加收藏专辑展示
This commit is contained in:
@@ -10,6 +10,11 @@ export default {
|
||||
trackCount: '{count} tracks',
|
||||
playCount: 'Played {count} times'
|
||||
},
|
||||
tabs: {
|
||||
created: 'Created',
|
||||
favorite: 'Favorite',
|
||||
album: 'Album'
|
||||
},
|
||||
ranking: {
|
||||
title: 'Listening History',
|
||||
playCount: '{count} times'
|
||||
|
||||
@@ -10,6 +10,11 @@ export default {
|
||||
trackCount: '{count}曲',
|
||||
playCount: '{count}回再生'
|
||||
},
|
||||
tabs: {
|
||||
created: '作成',
|
||||
favorite: 'お気に入り',
|
||||
album: 'アルバム'
|
||||
},
|
||||
ranking: {
|
||||
title: '聴取ランキング',
|
||||
playCount: '{count}回'
|
||||
|
||||
@@ -10,6 +10,11 @@ export default {
|
||||
trackCount: '{count}곡',
|
||||
playCount: '{count}회 재생'
|
||||
},
|
||||
tabs: {
|
||||
created: '생성',
|
||||
favorite: '즐겨찾기',
|
||||
album: '앨범'
|
||||
},
|
||||
ranking: {
|
||||
title: '음악 청취 순위',
|
||||
playCount: '{count}회'
|
||||
|
||||
@@ -10,6 +10,11 @@ export default {
|
||||
trackCount: '{count}首',
|
||||
playCount: '播放{count}次'
|
||||
},
|
||||
tabs: {
|
||||
created: '创建',
|
||||
favorite: '收藏',
|
||||
album: '专辑'
|
||||
},
|
||||
ranking: {
|
||||
title: '听歌排行',
|
||||
playCount: '{count}次'
|
||||
|
||||
@@ -10,6 +10,11 @@ export default {
|
||||
trackCount: '{count}首',
|
||||
playCount: '播放{count}次'
|
||||
},
|
||||
tabs: {
|
||||
created: '建立',
|
||||
favorite: '收藏',
|
||||
album: '專輯'
|
||||
},
|
||||
ranking: {
|
||||
title: '聽歌排行',
|
||||
playCount: '{count}次'
|
||||
|
||||
@@ -176,3 +176,15 @@ export function subscribePlaylist(params: { t: number; id: number }) {
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 收藏/取消收藏专辑
|
||||
* @param params t: 1 收藏, 2 取消收藏; id: 专辑id
|
||||
*/
|
||||
export function subscribeAlbum(params: { t: number; id: number }) {
|
||||
return request({
|
||||
url: '/album/sub',
|
||||
method: 'post',
|
||||
params
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,3 +72,15 @@ export const getUserPlaylists = (params: { uid: string | number }) => {
|
||||
params
|
||||
});
|
||||
};
|
||||
|
||||
// 获取已收藏专辑列表
|
||||
export const getUserAlbumSublist = (params?: { limit?: number; offset?: number }) => {
|
||||
return request({
|
||||
url: '/album/sublist',
|
||||
method: 'get',
|
||||
params: {
|
||||
limit: params?.limit || 25,
|
||||
offset: params?.offset || 0
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref } from 'vue';
|
||||
|
||||
import { logout } from '@/api/login';
|
||||
import { getLikedList } from '@/api/music';
|
||||
import { getUserAlbumSublist } from '@/api/user';
|
||||
import { clearLoginStatus } from '@/utils/auth';
|
||||
|
||||
interface UserData {
|
||||
@@ -27,6 +28,8 @@ export const useUserStore = defineStore('user', () => {
|
||||
);
|
||||
const searchValue = ref('');
|
||||
const searchType = ref(1);
|
||||
// 收藏的专辑 ID 列表
|
||||
const collectedAlbumIds = ref<Set<number>>(new Set());
|
||||
|
||||
// 方法
|
||||
const setUser = (userData: UserData) => {
|
||||
@@ -69,6 +72,39 @@ export const useUserStore = defineStore('user', () => {
|
||||
searchType.value = type;
|
||||
};
|
||||
|
||||
// 初始化收藏的专辑列表
|
||||
const initializeCollectedAlbums = async () => {
|
||||
if (!user.value || !localStorage.getItem('token')) {
|
||||
collectedAlbumIds.value.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await getUserAlbumSublist({ limit: 1000, offset: 0 });
|
||||
const albumIds = (data?.data || []).map((album: any) => album.id);
|
||||
collectedAlbumIds.value = new Set(albumIds);
|
||||
console.log(`已加载 ${albumIds.length} 个收藏专辑`);
|
||||
} catch (error) {
|
||||
console.error('获取收藏专辑列表失败:', error);
|
||||
collectedAlbumIds.value.clear();
|
||||
}
|
||||
};
|
||||
|
||||
// 添加收藏专辑
|
||||
const addCollectedAlbum = (albumId: number) => {
|
||||
collectedAlbumIds.value.add(albumId);
|
||||
};
|
||||
|
||||
// 移除收藏专辑
|
||||
const removeCollectedAlbum = (albumId: number) => {
|
||||
collectedAlbumIds.value.delete(albumId);
|
||||
};
|
||||
|
||||
// 检查专辑是否已收藏
|
||||
const isAlbumCollected = (albumId: number) => {
|
||||
return collectedAlbumIds.value.has(albumId);
|
||||
};
|
||||
|
||||
// 初始化
|
||||
const initializeUser = async () => {
|
||||
const savedUser = getLocalStorageItem<UserData | null>('user', null);
|
||||
@@ -77,6 +113,9 @@ export const useUserStore = defineStore('user', () => {
|
||||
// 如果用户已登录,获取收藏列表
|
||||
if (localStorage.getItem('token')) {
|
||||
try {
|
||||
// 同时初始化收藏专辑列表
|
||||
await initializeCollectedAlbums();
|
||||
|
||||
const { data } = await getLikedList(savedUser.userId);
|
||||
return data?.ids || [];
|
||||
} catch (error) {
|
||||
@@ -94,6 +133,7 @@ export const useUserStore = defineStore('user', () => {
|
||||
loginType,
|
||||
searchValue,
|
||||
searchType,
|
||||
collectedAlbumIds,
|
||||
|
||||
// 方法
|
||||
setUser,
|
||||
@@ -101,6 +141,10 @@ export const useUserStore = defineStore('user', () => {
|
||||
handleLogout,
|
||||
setSearchValue,
|
||||
setSearchType,
|
||||
initializeUser
|
||||
initializeUser,
|
||||
initializeCollectedAlbums,
|
||||
addCollectedAlbum,
|
||||
removeCollectedAlbum,
|
||||
isAlbumCollected
|
||||
};
|
||||
});
|
||||
|
||||
@@ -153,7 +153,12 @@
|
||||
object-fit="cover"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="listInfo?.creator" class="creator-info">
|
||||
<!-- 歌单显示创建者,专辑显示艺术家 -->
|
||||
<div v-if="isAlbum && listInfo?.artist" class="creator-info">
|
||||
<n-avatar round :size="24" :src="getImgUrl(listInfo.artist.picUrl, '50y50')" />
|
||||
<span class="creator-name">{{ listInfo.artist.name }}</span>
|
||||
</div>
|
||||
<div v-else-if="!isAlbum && listInfo?.creator" class="creator-info">
|
||||
<n-avatar round :size="24" :src="getImgUrl(listInfo.creator.avatarUrl, '50y50')" />
|
||||
<span class="creator-name">{{ listInfo.creator.nickname }}</span>
|
||||
</div>
|
||||
@@ -226,12 +231,16 @@ import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
import { subscribePlaylist, updatePlaylistTracks } from '@/api/music';
|
||||
import { getMusicDetail } from '@/api/music';
|
||||
import {
|
||||
getMusicDetail,
|
||||
subscribeAlbum,
|
||||
subscribePlaylist,
|
||||
updatePlaylistTracks
|
||||
} from '@/api/music';
|
||||
import PlayBottom from '@/components/common/PlayBottom.vue';
|
||||
import SongItem from '@/components/common/SongItem.vue';
|
||||
import { useDownload } from '@/hooks/useDownload';
|
||||
import { useMusicStore, usePlayerStore, useRecommendStore } from '@/store';
|
||||
import { useMusicStore, usePlayerStore, useRecommendStore, useUserStore } from '@/store';
|
||||
import { SongResult } from '@/types/music';
|
||||
import { getImgUrl, isElectron, isMobile, setAnimationClass } from '@/utils';
|
||||
import { getLoginErrorMessage, hasPermission } from '@/utils/auth';
|
||||
@@ -241,11 +250,13 @@ const route = useRoute();
|
||||
const playerStore = usePlayerStore();
|
||||
const musicStore = useMusicStore();
|
||||
const recommendStore = useRecommendStore();
|
||||
const userStore = useUserStore();
|
||||
const message = useMessage();
|
||||
|
||||
// 从路由参数或状态管理获取数据
|
||||
const loading = ref(false);
|
||||
const isDailyRecommend = computed(() => route.query.type === 'dailyRecommend');
|
||||
const isAlbum = computed(() => route.query.type === 'album');
|
||||
const name = computed(() => {
|
||||
if (isDailyRecommend.value) {
|
||||
return t('comp.recommendSinger.songlist'); // 日推的标题
|
||||
@@ -333,7 +344,7 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
const getCoverImgUrl = computed(() => {
|
||||
const coverImgUrl = listInfo.value?.coverImgUrl;
|
||||
const coverImgUrl = listInfo.value?.coverImgUrl || listInfo.value?.picUrl;
|
||||
if (coverImgUrl) {
|
||||
return coverImgUrl;
|
||||
}
|
||||
@@ -801,19 +812,29 @@ const toggleLayout = () => {
|
||||
localStorage.setItem('musicListLayout', isCompactLayout.value ? 'compact' : 'normal');
|
||||
};
|
||||
|
||||
// 初始化歌单收藏状态
|
||||
// 初始化收藏状态(支持歌单和专辑)
|
||||
const checkCollectionStatus = () => {
|
||||
// 只有歌单类型才能收藏
|
||||
if (route.query.type === 'playlist' && listInfo.value?.id) {
|
||||
const type = route.query.type as string;
|
||||
|
||||
// 歌单类型的收藏检查
|
||||
if (type === 'playlist' && listInfo.value?.id) {
|
||||
canCollect.value = true;
|
||||
// 检查是否已收藏
|
||||
isCollected.value = listInfo.value.subscribed || false;
|
||||
} else {
|
||||
}
|
||||
// 专辑类型的收藏检查 - 使用 store 判断
|
||||
else if (type === 'album' && listInfo.value?.id) {
|
||||
canCollect.value = true;
|
||||
// 从 userStore 中判断是否已收藏
|
||||
isCollected.value = userStore.isAlbumCollected(listInfo.value.id);
|
||||
}
|
||||
// 其他类型不支持收藏
|
||||
else {
|
||||
canCollect.value = false;
|
||||
isCollected.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 切换收藏状态
|
||||
// 切换收藏状态(支持歌单和专辑)
|
||||
const toggleCollect = async () => {
|
||||
if (!listInfo.value?.id) return;
|
||||
|
||||
@@ -823,13 +844,23 @@ const toggleCollect = async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const type = route.query.type as string;
|
||||
|
||||
try {
|
||||
loadingList.value = true;
|
||||
const tVal = isCollected.value ? 2 : 1; // 1:收藏, 2:取消收藏
|
||||
const response = await subscribePlaylist({
|
||||
t: tVal,
|
||||
id: listInfo.value.id
|
||||
});
|
||||
|
||||
// 根据类型调用不同的API
|
||||
const response =
|
||||
type === 'album'
|
||||
? await subscribeAlbum({
|
||||
t: tVal,
|
||||
id: listInfo.value.id
|
||||
})
|
||||
: await subscribePlaylist({
|
||||
t: tVal,
|
||||
id: listInfo.value.id
|
||||
});
|
||||
|
||||
// 假设API返回格式是 { data: { code: number, msg?: string } }
|
||||
const res = response.data;
|
||||
@@ -840,13 +871,25 @@ const toggleCollect = async () => {
|
||||
? 'comp.musicList.collectSuccess'
|
||||
: 'comp.musicList.cancelCollectSuccess';
|
||||
message.success(t(msgKey));
|
||||
// 更新歌单信息
|
||||
listInfo.value.subscribed = isCollected.value;
|
||||
|
||||
// 更新收藏状态
|
||||
if (type === 'album') {
|
||||
// 专辑:更新 store 中的收藏状态
|
||||
if (isCollected.value) {
|
||||
userStore.addCollectedAlbum(listInfo.value.id);
|
||||
} else {
|
||||
userStore.removeCollectedAlbum(listInfo.value.id);
|
||||
}
|
||||
(listInfo.value as any).isSub = isCollected.value;
|
||||
} else {
|
||||
// 歌单:更新 listInfo 的状态
|
||||
listInfo.value.subscribed = isCollected.value;
|
||||
}
|
||||
} else {
|
||||
throw new Error(res.msg || t('comp.musicList.operationFailed'));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('收藏歌单失败:', error);
|
||||
console.error(`收藏${type === 'album' ? '专辑' : '歌单'}失败:`, error);
|
||||
message.error(t('comp.musicList.operationFailed'));
|
||||
} finally {
|
||||
loadingList.value = false;
|
||||
|
||||
@@ -32,41 +32,50 @@
|
||||
</div>
|
||||
<div class="uesr-signature">{{ userDetail.profile.signature }}</div>
|
||||
<div class="play-list" :class="setAnimationClass('animate__fadeInLeft')">
|
||||
<div class="title">
|
||||
<div>{{ t('user.playlist.created') }}</div>
|
||||
<div class="import-btn" @click="goToImportPlaylist" v-if="isElectron">
|
||||
{{ t('comp.playlist.import.button') }}
|
||||
</div>
|
||||
<div class="tab-container">
|
||||
<n-tabs v-model:value="currentTab" type="segment" animated>
|
||||
<n-tab v-for="tab in tabs" :key="tab.key" :name="tab.key" :tab="t(tab.label)">
|
||||
</n-tab>
|
||||
</n-tabs>
|
||||
</div>
|
||||
<n-scrollbar>
|
||||
<div
|
||||
v-for="(item, index) in playList"
|
||||
:key="index"
|
||||
class="play-list-item"
|
||||
@click="openPlaylist(item)"
|
||||
>
|
||||
<n-image
|
||||
:src="getImgUrl(item.coverImgUrl, '50y50')"
|
||||
class="play-list-item-img"
|
||||
lazy
|
||||
preview-disabled
|
||||
/>
|
||||
<div class="play-list-item-info">
|
||||
<div class="play-list-item-name">
|
||||
<n-ellipsis :line-clamp="1">{{ item.name }}</n-ellipsis>
|
||||
<div v-if="item.creator.userId === user.userId" class="playlist-creator-tag">
|
||||
{{ t('user.playlist.mine') }}
|
||||
<div class="mt-4">
|
||||
<button
|
||||
class="play-list-item"
|
||||
@click="goToImportPlaylist"
|
||||
v-if="isElectron && currentTab === 'created'"
|
||||
>
|
||||
<div class="play-list-item-img"><i class="icon iconfont ri-add-line"></i></div>
|
||||
<div class="play-list-item-info">
|
||||
<div class="play-list-item-name">
|
||||
{{ t('comp.playlist.import.button') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="play-list-item-count">
|
||||
{{ t('user.playlist.trackCount', { count: item.trackCount }) }},{{
|
||||
t('user.playlist.playCount', { count: item.playCount })
|
||||
}}
|
||||
</button>
|
||||
<div
|
||||
v-for="(item, index) in currentList"
|
||||
:key="index"
|
||||
class="play-list-item"
|
||||
@click="handleItemClick(item)"
|
||||
>
|
||||
<n-image
|
||||
:src="getImgUrl(getCoverUrl(item), '50y50')"
|
||||
class="play-list-item-img"
|
||||
lazy
|
||||
preview-disabled
|
||||
/>
|
||||
<div class="play-list-item-info">
|
||||
<div class="play-list-item-name">
|
||||
<n-ellipsis :line-clamp="1">{{ item.name }}</n-ellipsis>
|
||||
</div>
|
||||
<div class="play-list-item-count">
|
||||
{{ getItemDescription(item) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pb-20"></div>
|
||||
<play-bottom />
|
||||
</div>
|
||||
<div class="pb-20"></div>
|
||||
<play-bottom />
|
||||
</n-scrollbar>
|
||||
</div>
|
||||
</div>
|
||||
@@ -114,7 +123,7 @@ import { useI18n } from 'vue-i18n';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
import { getListDetail } from '@/api/list';
|
||||
import { getUserDetail, getUserPlaylist, getUserRecord } from '@/api/user';
|
||||
import { getUserAlbumSublist, getUserDetail, getUserPlaylist, getUserRecord } from '@/api/user';
|
||||
import { navigateToMusicList } from '@/components/common/MusicListNavigator';
|
||||
import PlayBottom from '@/components/common/PlayBottom.vue';
|
||||
import SongItem from '@/components/common/SongItem.vue';
|
||||
@@ -143,8 +152,70 @@ const list = ref<Playlist>();
|
||||
const listLoading = ref(false);
|
||||
const message = useMessage();
|
||||
|
||||
// Tab 相关
|
||||
const tabs = [
|
||||
{ key: 'created', label: 'user.tabs.created' },
|
||||
{ key: 'favorite', label: 'user.tabs.favorite' },
|
||||
{ key: 'album', label: 'user.tabs.album' }
|
||||
];
|
||||
const currentTab = ref('created');
|
||||
const albumList = ref<any[]>([]);
|
||||
|
||||
const user = computed(() => userStore.user);
|
||||
|
||||
// 创建的歌单(当前用户创建的)
|
||||
const createdPlaylists = computed(() => {
|
||||
if (!user.value) return [];
|
||||
return playList.value.filter((item) => item.creator?.userId === user.value!.userId);
|
||||
});
|
||||
|
||||
// 收藏的歌单(非当前用户创建的)
|
||||
const favoritePlaylists = computed(() => {
|
||||
if (!user.value) return [];
|
||||
return playList.value.filter((item) => item.creator?.userId !== user.value!.userId);
|
||||
});
|
||||
|
||||
// 当前显示的列表(根据 tab 切换)
|
||||
const currentList = computed(() => {
|
||||
switch (currentTab.value) {
|
||||
case 'created':
|
||||
return createdPlaylists.value;
|
||||
case 'favorite':
|
||||
return favoritePlaylists.value;
|
||||
case 'album':
|
||||
return albumList.value;
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
// 获取封面图片 URL
|
||||
const getCoverUrl = (item: any) => {
|
||||
return item.coverImgUrl || item.picUrl || '';
|
||||
};
|
||||
|
||||
// 获取列表项描述
|
||||
const getItemDescription = (item: any) => {
|
||||
if (currentTab.value === 'album') {
|
||||
// 专辑:显示艺术家和歌曲数量
|
||||
const artist = item.artist?.name || '';
|
||||
const size = item.size ? ` · ${item.size}首` : '';
|
||||
return `${artist}${size}`;
|
||||
} else {
|
||||
// 歌单:显示曲目数和播放量
|
||||
return `${t('user.playlist.trackCount', { count: item.trackCount })},${t('user.playlist.playCount', { count: item.playCount })}`;
|
||||
}
|
||||
};
|
||||
|
||||
// 统一处理列表项点击
|
||||
const handleItemClick = (item: any) => {
|
||||
if (currentTab.value === 'album') {
|
||||
openAlbum(item);
|
||||
} else {
|
||||
openPlaylist(item);
|
||||
}
|
||||
};
|
||||
|
||||
const goToImportPlaylist = () => {
|
||||
router.push('/playlist/import');
|
||||
};
|
||||
@@ -231,6 +302,23 @@ const loadData = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 加载专辑列表
|
||||
const loadAlbumList = async () => {
|
||||
try {
|
||||
infoLoading.value = true;
|
||||
const res = await getUserAlbumSublist({ limit: 100, offset: 0 });
|
||||
if (!mounted.value) return;
|
||||
albumList.value = res.data.data || [];
|
||||
} catch (error: any) {
|
||||
console.error('加载专辑列表失败:', error);
|
||||
message.error('加载专辑列表失败');
|
||||
} finally {
|
||||
if (mounted.value) {
|
||||
infoLoading.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 监听路由变化
|
||||
watch(
|
||||
() => router.currentRoute.value.path,
|
||||
@@ -255,6 +343,18 @@ watch(
|
||||
}
|
||||
);
|
||||
|
||||
// 监听 tab 切换
|
||||
watch(currentTab, async (newTab) => {
|
||||
if (newTab === 'album') {
|
||||
// 刷新收藏专辑列表到 store
|
||||
await userStore.initializeCollectedAlbums();
|
||||
// 如果本地列表为空,则加载
|
||||
if (albumList.value.length === 0) {
|
||||
loadAlbumList();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 页面挂载时检查登录状态
|
||||
onMounted(() => {
|
||||
checkLoginStatus() && loadData();
|
||||
@@ -279,6 +379,38 @@ const openPlaylist = (item: any) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 打开专辑
|
||||
const openAlbum = async (item: any) => {
|
||||
// 使用专辑 API 获取专辑详情
|
||||
try {
|
||||
listLoading.value = true;
|
||||
const { getAlbumDetail } = await import('@/api/music');
|
||||
const res = await getAlbumDetail(item.id.toString());
|
||||
|
||||
if (res.data?.album && res.data?.songs) {
|
||||
const albumData = res.data.album;
|
||||
const songs = res.data.songs.map((item) => ({
|
||||
...item,
|
||||
picUrl: albumData.picUrl
|
||||
}));
|
||||
|
||||
navigateToMusicList(router, {
|
||||
id: item.id,
|
||||
type: 'album',
|
||||
name: albumData.name,
|
||||
songList: songs,
|
||||
listInfo: albumData,
|
||||
canRemove: false // 专辑不支持移除歌曲
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载专辑失败:', error);
|
||||
message.error('加载专辑失败');
|
||||
} finally {
|
||||
listLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handlePlay = () => {
|
||||
const tracks = recordList.value || [];
|
||||
playerStore.setPlayList(tracks);
|
||||
@@ -321,13 +453,7 @@ const currentLoginType = computed(() => userStore.loginType);
|
||||
.title {
|
||||
@apply text-lg font-bold flex items-center justify-between;
|
||||
@apply text-gray-900 dark:text-white;
|
||||
.import-btn {
|
||||
@apply bg-light-100 font-normal rounded-lg px-2 py-1 text-opacity-70 text-sm hover:bg-light-200 hover:text-green-500 dark:bg-dark-200 dark:hover:bg-dark-300 dark:hover:text-green-400;
|
||||
@apply cursor-pointer;
|
||||
@apply transition-all duration-200;
|
||||
}
|
||||
}
|
||||
|
||||
.user-name {
|
||||
@apply text-xl font-bold mb-4 flex justify-between;
|
||||
@apply text-white text-opacity-70;
|
||||
@@ -393,14 +519,15 @@ const currentLoginType = computed(() => userStore.loginType);
|
||||
}
|
||||
|
||||
&-item {
|
||||
@apply flex items-center px-2 py-1 rounded-xl cursor-pointer;
|
||||
@apply flex items-center px-2 py-2 rounded-xl cursor-pointer w-full;
|
||||
@apply transition-all duration-200;
|
||||
@apply hover:bg-light-200 dark:hover:bg-dark-200;
|
||||
|
||||
&-img {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
@apply rounded-xl;
|
||||
@apply flex items-center justify-center rounded-xl text-[40px] w-[60px] h-[60px] bg-light-300 dark:bg-dark-300;
|
||||
.iconfont {
|
||||
@apply text-[40px];
|
||||
}
|
||||
}
|
||||
|
||||
&-info {
|
||||
@@ -442,4 +569,11 @@ const currentLoginType = computed(() => userStore.loginType);
|
||||
@apply flex justify-center items-center h-full w-full;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.n-tabs-rail) {
|
||||
@apply rounded-xl overflow-hidden !important;
|
||||
.n-tabs-capsule {
|
||||
@apply rounded-xl !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user