feat: 优化歌词进度 添加下载 优化播放 优化历史记录

This commit is contained in:
alger
2024-11-28 08:12:37 +08:00
parent dc12d895d8
commit d925f40303
9 changed files with 200 additions and 41 deletions
+114
View File
@@ -0,0 +1,114 @@
<template>
<n-modal v-model:show="showModal" preset="dialog" :show-icon="false" :mask-closable="true" class="install-app-modal">
<div class="modal-content">
<div class="modal-header">
<div class="app-icon">
<img src="@/assets/logo.png" alt="App Icon" />
</div>
<div class="app-info">
<h2 class="app-name">Alger Music</h2>
<p class="app-desc">在桌面安装应用获得更好的体验</p>
</div>
</div>
<div class="modal-actions">
<n-button class="cancel-btn" @click="closeModal">暂不安装</n-button>
<n-button type="primary" class="install-btn" @click="handleInstall">立即安装</n-button>
</div>
</div>
</n-modal>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
const showModal = ref(false);
const isElectron = ref((window as any).electron !== undefined);
const closeModal = () => {
showModal.value = false;
localStorage.setItem('installPromptDismissed', 'true');
};
const handleInstall = async () => {
// 新页面打开
// 识别当前环境是 mac 还是 windows
const os = navigator.platform;
const isMac = os.includes('Mac');
const isWindows = os.includes('Win');
const urls = {
mac: 'http://file.alger.fun/d/ali/%E8%BD%AF%E4%BB%B6/AlgerMusic/AlgerMusic.dmg',
windows: 'http://file.alger.fun/d/ali/%E8%BD%AF%E4%BB%B6/AlgerMusic/AlgerMusic_2.1.0_Setup_x64.exe',
};
// 根据操作系统选择下载链接
let downloadUrl = '';
if (isMac) {
downloadUrl = urls.mac;
} else if (isWindows) {
downloadUrl = urls.windows;
}
if (downloadUrl) {
window.open(downloadUrl, '_blank');
}
};
onMounted(() => {
// 如果是 electron 环境,不显示安装提示
if (isElectron.value) {
return;
}
// 检查是否已经点击过"暂不安装"
const isDismissed = localStorage.getItem('installPromptDismissed') === 'true';
if (isDismissed) {
return;
}
showModal.value = true;
});
</script>
<style lang="scss" scoped>
.install-app-modal {
:deep(.n-modal) {
@apply max-w-sm;
}
.modal-content {
@apply p-4;
.modal-header {
@apply flex items-center mb-6;
.app-icon {
@apply w-16 h-16 mr-4 rounded-2xl overflow-hidden;
img {
@apply w-full h-full object-cover;
}
}
.app-info {
@apply flex-1;
.app-name {
@apply text-xl font-bold mb-1;
}
.app-desc {
@apply text-sm text-gray-400;
}
}
}
.modal-actions {
@apply flex gap-3;
.n-button {
@apply flex-1;
}
.cancel-btn {
@apply bg-gray-800 text-gray-300 border-none;
&:hover {
@apply bg-gray-700;
}
}
.install-btn {
@apply bg-green-600 border-none;
&:hover {
@apply bg-green-500;
}
}
}
}
}
</style>
+57 -7
View File
@@ -1,5 +1,5 @@
<template>
<div class="song-item" :class="{ 'song-mini': mini }">
<div class="song-item" :class="{ 'song-mini': mini, 'song-list': list }">
<n-image
v-if="item.picUrl"
ref="songImg"
@@ -12,18 +12,29 @@
@load="imageLoad"
/>
<div class="song-item-content">
<div class="song-item-content-title">
<n-ellipsis class="text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
</div>
<div class="song-item-content-name">
<n-ellipsis class="text-ellipsis" line-clamp="1">
<div v-if="list" class="song-item-content-wrapper">
<n-ellipsis class="song-item-content-title text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
<div class="song-item-content-divider">-</div>
<n-ellipsis class="song-item-content-name text-ellipsis" line-clamp="1">
<span v-for="(artists, artistsindex) in item.ar || item.song.artists" :key="artistsindex"
>{{ artists.name }}{{ artistsindex < (item.ar || item.song.artists).length - 1 ? ' / ' : '' }}</span
>
</n-ellipsis>
</div>
<template v-else>
<div class="song-item-content-title">
<n-ellipsis class="text-ellipsis" line-clamp="1">{{ item.name }}</n-ellipsis>
</div>
<div class="song-item-content-name">
<n-ellipsis class="text-ellipsis" line-clamp="1">
<span v-for="(artists, artistsindex) in item.ar || item.song.artists" :key="artistsindex"
>{{ artists.name }}{{ artistsindex < (item.ar || item.song.artists).length - 1 ? ' / ' : '' }}</span
>
</n-ellipsis>
</div>
</template>
</div>
<div class="song-item-operating">
<div class="song-item-operating" :class="{ 'song-item-operating-list': list }">
<div class="song-item-operating-like">
<i class="iconfont icon-likefill"></i>
</div>
@@ -51,9 +62,11 @@ const props = withDefaults(
defineProps<{
item: SongResult;
mini?: boolean;
list?: boolean;
}>(),
{
mini: false,
list: false,
},
);
@@ -175,4 +188,41 @@ const playMusicEvent = async (item: SongResult) => {
}
}
}
.song-list {
@apply p-2 rounded-lg hover:bg-gray-800/50 border border-gray-800/50 mb-2;
.song-item-img {
@apply w-10 h-10 rounded-lg mr-3;
}
.song-item-content {
@apply flex items-center flex-1;
&-wrapper {
@apply flex items-center flex-1 text-sm;
}
&-title {
@apply text-white flex-shrink-0 max-w-[45%];
}
&-divider {
@apply mx-2 text-gray-400;
}
&-name {
@apply text-gray-400 flex-1 min-w-0;
}
}
.song-item-operating {
@apply flex items-center gap-2;
&-like {
@apply cursor-pointer hover:scale-110 transition-transform;
.iconfont {
@apply text-base text-gray-400 hover:text-red-500;
}
}
&-play {
@apply w-7 h-7 cursor-pointer hover:scale-110 transition-transform;
.iconfont {
@apply text-base;
}
}
}
}
</style>