From d4444bbea0815a187fb635fb92d63878417195f4 Mon Sep 17 00:00:00 2001 From: zhangda <221830074@smail.nju.edu.cn> Date: Mon, 23 Dec 2024 17:35:06 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E4=B8=AD=E9=97=B4=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=E8=BF=94=E5=9B=9E=E4=B8=8A=E4=B8=80=E6=AC=A1=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E7=9A=84=E6=96=B9=E5=BC=8F=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=90=84=E4=B8=AA=E5=9C=B0=E6=96=B9=E6=92=AD=E6=94=BE=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E4=B8=8D=E4=B8=80=E8=87=B4=E7=9A=84bug=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E5=BD=93=E5=89=8D=E6=92=AD=E6=94=BE=E6=AD=8C=E6=9B=B2?= =?UTF-8?q?=E4=B8=8D=E5=9C=A8=E5=BD=93=E5=89=8D=E4=B8=93=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E4=BD=86=E5=BD=93=E5=89=8D=E4=B8=93=E8=BE=91=E5=8D=B4=E5=A4=84?= =?UTF-8?q?=E4=BA=8E=E6=92=AD=E6=94=BE=E7=8A=B6=E6=80=81=E7=9A=84bug=20?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E8=AF=84=E8=AE=BA=E5=8C=BA=E6=A0=B7=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ArtistView.vue | 335 ++---------------------------- src/components/Comment.vue | 328 +++++++++++++++++------------ src/components/MusicAlbumView.vue | 64 +++++- src/components/SearchView.vue | 48 ++++- src/router/index.js | 14 +- src/views/HomePage.vue | 70 ++++--- 6 files changed, 362 insertions(+), 497 deletions(-) diff --git a/src/components/ArtistView.vue b/src/components/ArtistView.vue index 2d1c5c6..82f4a47 100644 --- a/src/components/ArtistView.vue +++ b/src/components/ArtistView.vue @@ -3,13 +3,13 @@ import {computed, nextTick, onMounted, onUnmounted, ref, watch} from "vue"; import playButton from "../icon/playButton.vue"; import pauseButton from "../icon/pauseButton.vue"; import {backgroundColor, updateBackground} from "../utils/getBackgroundColor"; -import {getSongsByArtist, getArtistInfo} from "../api/artist"; +import {getArtistInfo} from "../api/artist"; import {getSongById} from "../api/resolve"; import checkMark from "../icon/checkMark.vue"; import {addSongToPlaylist, removeSongFromPlaylist} from "../api/playlist"; import {getSongsByPlaylist} from "../api/song"; -import { formatTime } from '../utils/formatTime'; -import { loadSongDurations } from '../utils/loadSongDurations'; +import {formatTime} from '../utils/formatTime'; +import {loadSongDurations} from '../utils/loadSongDurations'; const emit = defineEmits(['playSong', 'pauseSong', 'back', 'updateSongs']); const props = defineProps({ @@ -183,6 +183,10 @@ onMounted(() => { resizeObserver.value.observe(albumContent); } }); + + musicPlayIndex = props.currentSongId; + musicClickedIndex = props.currentSongId; + musicPauseIndex = props.isPaused ? props.currentSongId : null; }); onUnmounted(() => { @@ -309,13 +313,17 @@ watch(() => hotSongs.value, (newSongs) => { loadSongDurations(newSongs, songDurations); }, { immediate: true }); -// 鐩戝惉currentSongId鐨勫彉鍖� watch(() => props.currentSongId, (newId) => { if (newId) { musicPlayIndex = newId; musicClickedIndex = newId; musicPauseIndex = props.isPaused ? newId : null; } +}, { immediate: true }); + +const isCurrentSongInList = computed(() => { + if (!props.currentSongId || !hotSongs.value || hotSongs.value.length === 0) return false; + return hotSongs.value.some(song => song.id === musicPlayIndex); }); </script> @@ -341,10 +349,10 @@ watch(() => props.currentSongId, (newId) => { <div class="content"> <div class="play-area"> <div class="play-button"> - <play-button v-if="musicPlayIndex===null||musicPauseIndex!==null" + <play-button v-if="!isCurrentSongInList||musicPauseIndex!==null" @click="playFromId(musicPauseIndex)" style="position: absolute; top:20%;left:24%;color: #000000"/> - <pause-button v-if="musicPlayIndex!==null&&musicPauseIndex===null" + <pause-button v-if="isCurrentSongInList&&musicPauseIndex===null" @click="pauseMusic(musicPlayIndex)" style="position: absolute; top:24%;left:25%;color: #000000"/> </div> @@ -837,321 +845,6 @@ li:hover { } } -/* new-elements */ -.edit-desc { - visibility: hidden; - z-index: 1000; - background-color: rgba(0, 0, 0, .7); - bottom: 0; - display: flex; - left: 0; - position: absolute; - right: 0; - top: 0; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - overflow: hidden; -} - -.main-edit-desc { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-orient: vertical; - -webkit-box-direction: normal; - background-color: #282828; - border-radius: 8px; - -webkit-box-shadow: 0 4px 4px rgba(0, 0, 0, .3); - box-shadow: 0 4px 4px rgba(0, 0, 0, .3); - color: #fff; - -ms-flex-direction: column; - flex-direction: column; - min-height: 384px; - width: 524px; -} - -.edit-desc-header { - display: flex; - -webkit-box-pack: justify; - -ms-flex-pack: justify; - justify-content: space-between; - padding: 24px; -} - -.edit-desc-header-button { - align-self: end; - background-color: transparent; - border: 0; - border-radius: 32px; - color: hsla(0, 0%, 100%, .7); - grid-area: close-button; - height: 32px; - margin-top: -8px; - width: 32px; - -webkit-margin-end: -8px; - margin-inline-end: -8px; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -.edit-desc-text { - display: grid; - grid-template: 32px 132px 32px auto / 180px 1fr; - grid-template-areas: - "album-image title" - "album-image description" - ". save-button" - "disclaimer disclaimer"; - grid-gap: 16px; - padding: 0 24px 24px; -} - -.edit-desc-img { - grid-area: album-image; - height: 180px; - margin: 0; - position: relative; - /* width: 180px; */ -} - -.edit-desc-img-1 { - border-radius: 4px; - height: 100%; - width: 100%; -} - -.edit-desc-img-1-1 { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -ms-flex-pack: center; - background-color: #282828; - color: #7f7f7f; - justify-content: center; - -webkit-box-shadow: 0 4px 60px rgba(0, 0, 0, .5); - box-shadow: 0 4px 60px rgba(0, 0, 0, .5); - - &:hover { - display: none; - } -} - -.large-svg { - fill: currentcolor; - width: 48px; - height: 48px; -} - -.edit-desc-img-2 { - bottom: 0; - left: 0; - position: absolute; - right: 0; - top: 0; -} - -.edit-desc-img-2-1 { - height: 100%; - width: 100%; -} - -.edit-desc-img-2-button { - background-color: #282828; - color: #fff; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - text-align: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -ms-flex-pack: center; - border: none; - border-radius: 4px; - justify-content: center; - opacity: 0; - padding: 0; -} - -.edit-desc-img-2-1-1 { - margin-top: 16px; - -webkit-transition: opacity .2s; - transition: opacity .2s; -} - -.edit-desc-img-3 { - right: 8px; - height: 32px; - position: absolute; - top: 8px; - width: 32px; -} - -@media (hover: hover) { - .edit-desc-img-3-button:not([data-context-menu-open=true]) { - opacity: 0; - pointer-events: none; - position: unset; - } -} - -.edit-desc-img-3-button { - background-color: rgba(0, 0, 0, .3); - border: none; - border-radius: 500px; - color: #b3b3b3; - display: -webkit-box; - display: -ms-flexbox; - display: flex; - padding: 8px; - text-decoration: none; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -ms-flex-pack: center; - justify-content: center; - - &:hover { - opacity: 0; - pointer-events: none; - position: unset; - } -} - -.small-svg { - height: 16px; - width: 16px; -} - -.edit-desc-input-name { - grid-area: title; - position: relative; - margin-right: 8px; -} - -.edit-desc-input-name-1 { - background: hsla(0, 0%, 100%, .1); - border: 1px solid transparent; - border-radius: 4px; - color: #fff; - font-family: inherit; - font-size: 14px; - height: 40px; - padding: 0 12px; - width: 100%; - -webkit-box-shadow: inset 0 -2px #343030; - box-shadow: inset 0 -2px 0 0 #343030; -} - -.edit-desc-input-desc { - grid-area: description; - margin-top: 8px; - position: relative; -} - -.edit-desc-input-desc-1 { - background: hsla(0, 0%, 100%, .1); - border: 1px solid transparent; - border-radius: 4px; - color: #fff; - font-family: inherit; - font-size: 14px; - padding: 8px 8px 28px; - resize: none; - width: 100%; - height: 70%; -} - -.edit-desc-button { - display: -webkit-box; - display: -ms-flexbox; - display: flex; - grid-area: save-button; - justify-self: flex-end; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; -} - -.edit-desc-button-1 { - box-sizing: border-box; - -webkit-tap-highlight-color: transparent; - background-color: transparent; - border: 0; - border-radius: 9999px; - cursor: pointer; - display: inline-block; - position: relative; - text-align: center; - text-decoration: none; - text-transform: none; - touch-action: manipulation; - transition-duration: 33ms; - transition-property: background-color, border-color, color, box-shadow, filter, transform; - user-select: none; - vertical-align: middle; - transform: translate3d(0px, 0px, 0px); - padding: 0px; - min-inline-size: 0px; - align-self: center; -} - -.edit-desc-button-1-1 { - box-sizing: border-box; - -webkit-tap-highlight-color: transparent; - position: relative; - background-color: #ffffff; - color: #000000; - display: flex; - border-radius: 9999px; - font-size: inherit; - min-block-size: 48px; - -webkit-box-align: center; - align-items: center; - -webkit-box-pack: center; - justify-content: center; - padding-block: 8px; - padding-inline: 32px; - transition-property: background-color, transform; - transition-duration: 33ms; -} - -.encore-text { - -webkit-box-sizing: border-box; - box-sizing: border-box; - -webkit-tap-highlight-color: transparent; - color: inherit; - margin-block: 0; - font-size: 13px; - white-space: normal; -} - -.encore-text-title-small { - font-size: 1.5rem; -} - -.final-tip { - grid-area: disclaimer; -} - -.encore-text-marginal-bold { - font-weight: 700; -} - .follow-button { margin-left: 32px; padding: 8px 20px; diff --git a/src/components/Comment.vue b/src/components/Comment.vue index c605395..e44db22 100644 --- a/src/components/Comment.vue +++ b/src/components/Comment.vue @@ -11,6 +11,8 @@ import {useTheme} from "../store/theme"; import Pagination from "../components/Pagination.vue"; import {getDominantColor} from "../utils/getBackgroundColor"; +const emit = defineEmits(['back']); + const theme = useTheme() const state = reactive({ comments: [], @@ -46,7 +48,7 @@ const sortBy = ref('Time') // 榛樿鎸夋椂闂存帓搴� 瑕嗙洊浠撳簱鐨凜omment.vue */ const backgroundColor = ref("#ffffff"); -const gradientColor = computed(() => `linear-gradient(to bottom, ${backgroundColor.value} , #1F1F1F 50%)`) +const gradientColor = computed(() => `linear-gradient(to bottom, ${backgroundColor.value} 0%, #121212 100%)`); onMounted(() => { watch(bg, (val) => { @@ -199,7 +201,7 @@ const handleSubmit = () => { songId: parseInt(songId), comment: comment.value, }).then(() => { - ElMessage.success("璇勮鎴愬姛锛�"); + // ElMessage.success("璇勮鎴愬姛锛�"); comment.value = ""; getCommentCount(parseInt(songId)); @@ -207,7 +209,7 @@ const handleSubmit = () => { sortBy.value = 'Time' getCommentMusicFn(parseInt(songId), 1); }).catch(error => { - ElMessage.error("鍙戝竷璇勮澶辫触锛岃绋嶅悗閲嶈瘯"); + // ElMessage.error("鍙戝竷璇勮澶辫触锛岃绋嶅悗閲嶈瘯"); console.error("Submit comment failed:", error); }); } @@ -250,7 +252,7 @@ const handleLike = (index) => { ? comment.likeCount + 1 : comment.likeCount - 1; }).catch(error => { - ElMessage.error("鐐硅禐澶辫触锛岃绋嶅悗閲嶈瘯"); + // ElMessage.error("鐐硅禐澶辫触锛岃绋嶅悗閲嶈瘯"); console.error("Like failed:", error); }); } @@ -263,139 +265,145 @@ const changeSortBy = (type) => { <template> <div class="comment-wrapper" :style="{backgroundImage: gradientColor}"> - <div class="comment"> - <div v-if="state.song !== null" class="comment-box"> - <div class="info"> - <div ref="imgEl" class="bg-img"></div> - <div class="song-info"> - <div class="song-name">{{ state.song.title }}</div> - <div class="singers"> - <div class="singer-info"> - <span>姝屾墜:{{ state.song.artist }}</span> - <!--<span v-for="(item, index) in state.song.singer">--> - <!--姝屾墜:{{item.name + (index < state.song.singer.length - 1 ? '/' : '') }}--> - <!--</span>--> + <div class="back-button" data-tooltip="杩斿洖" @click="$emit('back')"> + <svg height="16" width="16" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.03.47a.75.75 0 0 1 0 1.06L4.56 8l6.47 6.47a.75.75 0 1 1-1.06 1.06L2.44 8 9.97.47a.75.75 0 0 1 1.06 0z"></path> + </svg> + </div> + + <div class="comment"> + <div v-if="state.song !== null" class="comment-box"> + <div class="info"> + <div ref="imgEl" class="bg-img"></div> + <div class="song-info"> + <div class="song-name">{{ state.song.title }}</div> + <div class="singers"> + <div class="singer-info"> + <span>姝屾墜:{{ state.song.artist }}</span> + <!--<span v-for="(item, index) in state.song.singer">--> + <!--姝屾墜:{{item.name + (index < state.song.singer.length - 1 ? '/' : '') }}--> + <!--</span>--> + </div> </div> </div> </div> - </div> - <div class="navigation"> - <div class="nav-left active" @click="showComments">璇勮{{ state.total }}</div> - <div class="nav-right" @click="showDetails">璇︽儏</div> - </div> - <div v-if="showComment" class="user-comment"> - <textarea placeholder="璇疯緭鍏ユ偍鐨勮瘎璁�..." v-model="comment" @input="adjustHeight"></textarea> - <span - class="custom-button" - style="color: white; font-size: 20px; position: absolute; bottom: 14px; right: 2%" - @click.stop="handleSubmit" - >鍙戝竷</span> - </div> - <div v-if="showComment" class="comment-content"> - <div class="comment-content-box"> - <div class="title-container"> - <div class="title">绮惧僵璇勮</div> - <div class="sort-options"> - <span - :class="{ active: sortBy === 'Time' }" - @click="changeSortBy('Time')" - >鏈€鏂�</span> - <div class="divider"></div> - <span - :class="{ active: sortBy === 'Hot' }" - @click="changeSortBy('Hot')" - >鏈€鐑�</span> + <div class="navigation"> + <div class="nav-left active" @click="showComments">璇勮{{ state.total }}</div> + <div class="nav-right" @click="showDetails">璇︽儏</div> + </div> + <div v-if="showComment" class="user-comment"> + <textarea placeholder="璇疯緭鍏ユ偍鐨勮瘎璁�..." v-model="comment" @input="adjustHeight"></textarea> + <span + class="custom-button" + style="color: white; font-size: 20px; position: absolute; bottom: 14px; right: 2%" + @click.stop="handleSubmit" + >鍙戝竷</span> + </div> + <div v-if="showComment" class="comment-content"> + <div class="comment-content-box"> + <div class="title-container"> + <div class="title">绮惧僵璇勮</div> + <div class="sort-options"> + <span + :class="{ active: sortBy === 'Time' }" + @click="changeSortBy('Time')" + >鏈€鏂�</span> + <div class="divider"></div> + <span + :class="{ active: sortBy === 'Hot' }" + @click="changeSortBy('Hot')" + >鏈€鐑�</span> + </div> </div> - </div> - <div class="content" @wheel.stop> - <div v-for="i in state.comments.length" class="content-line"> - <!-- :style="{ backgroundImage: `url(${state.commenters[i - 1].avatarUrl})` }"--> - <div - @click="gotoUserDetail(state.commenters[i - 1].userId)" - :style="{ backgroundImage: '../assets/pictures/avatar.png' }" - class="photo" - ></div> - <div v-if="state.commenters[i - 1] !== undefined" class="right-box"> - <div class="comment-text"> - <div @click="gotoUserDetail(state.comments[i - 1].id)" class="name"> - {{ state.commenters[i - 1].username }}: + <div class="content" @wheel.stop> + <div v-for="i in state.comments.length" class="content-line"> + <!-- :style="{ backgroundImage: `url(${state.commenters[i - 1].avatarUrl})` }"--> + <div + @click="gotoUserDetail(state.commenters[i - 1].userId)" + :style="{ backgroundImage: '../assets/pictures/avatar.png' }" + class="photo" + ></div> + <div v-if="state.commenters[i - 1] !== undefined" class="right-box"> + <div class="comment-text"> + <div @click="gotoUserDetail(state.comments[i - 1].id)" class="name"> + {{ state.commenters[i - 1].username }}: + </div> + <div class="text">{{ state.comments[i - 1].comment }}</div> </div> - <div class="text">{{ state.comments[i - 1].comment }}</div> - </div> - <div class="handle-box"> - <div class="time">{{ parseTime(state.comments[i - 1].createdAt) }}</div> - <div class="operation"> - <img - :src="likeIcon" - class="like-icon" - :class="{ 'liked': state.comments[i-1].isLiked }" - alt="like" - @click="handleLike(i-1)" - /> - <span - :class="{ 'liked-count': state.comments[i-1].isLiked }" - style="font-size: 12px;color: white" - >{{ state.comments[i - 1].likeCount }} - </span> - <div class="operator-line"></div> + <div class="handle-box"> + <div class="time">{{ parseTime(state.comments[i - 1].createdAt) }}</div> + <div class="operation"> + <img + :src="likeIcon" + class="like-icon" + :class="{ 'liked': state.comments[i-1].isLiked }" + alt="like" + @click="handleLike(i-1)" + /> + <span + :class="{ 'liked-count': state.comments[i-1].isLiked }" + style="font-size: 12px;color: white" + >{{ state.comments[i - 1].likeCount }} + </span> + <div class="operator-line"></div> + </div> </div> </div> + <div class="line"></div> </div> - <div class="line"></div> </div> + <pagination + class="pagination" + @current-change="currentChange" + :total="state.total" + :pageSize="state.pageSize" + :currentPage="state.currentPage" + :background="true" + layout="prev, pager, next" + /> </div> - <pagination - class="pagination" - @current-change="currentChange" - :total="state.total" - :pageSize="state.pageSize" - :currentPage="state.currentPage" - :background="true" - layout="prev, pager, next" - /> </div> - </div> - <div v-if="showDetail" class="song-info-container"> - <div class="song-info-row" v-if="state.song.title"> - <div class="song-info-label">姝屾洸:</div> - <div class="song-info-value">{{ state.song.title }}</div> - </div> - <div class="song-info-row" v-if="state.song.artist"> - <div class="song-info-label">鑹轰汉:</div> - <div class="song-info-value">{{ state.song.artist }}</div> - </div> - <div class="song-info-row" v-if="state.song.album"> - <div class="song-info-label">涓撹緫:</div> - <div class="song-info-value">{{ state.song.album }}</div> - </div> - <div class="song-info-row" v-if="state.song.lyricist"> - <div class="song-info-label">浣滆瘝:</div> - <div class="song-info-value">{{ state.song.lyricist }}</div> - </div> - <div class="song-info-row" v-if="state.song.composer"> - <div class="song-info-label">浣滄洸:</div> - <div class="song-info-value">{{ state.song.composer }}</div> - </div> - <div class="song-info-row" v-if="state.song.language"> - <div class="song-info-label">姝屾洸璇:</div> - <div class="song-info-value">{{ state.song.language }}</div> - </div> - <div class="song-info-row" v-if="state.song.genre"> - <div class="song-info-label">姝屾洸娴佹淳:</div> - <div class="song-info-value">{{ state.song.genre }}</div> - </div> - <div class="song-info-row" v-if="state.song.recordCompany"> - <div class="song-info-label">鍞辩墖鍏徃:</div> - <div class="song-info-value">{{ state.song.recordCompany }}</div> - </div> - <div class="song-info-row" v-if="state.song.description"> - <div class="song-info-label">璇︾粏浠嬬粛:</div> - <div class="song-info-value">{{ state.song.description }}</div> + <div v-if="showDetail" class="song-info-container"> + <div class="song-info-row" v-if="state.song.title"> + <div class="song-info-label">姝屾洸:</div> + <div class="song-info-value">{{ state.song.title }}</div> + </div> + <div class="song-info-row" v-if="state.song.artist"> + <div class="song-info-label">鑹轰汉:</div> + <div class="song-info-value">{{ state.song.artist }}</div> + </div> + <div class="song-info-row" v-if="state.song.album"> + <div class="song-info-label">涓撹緫:</div> + <div class="song-info-value">{{ state.song.album }}</div> + </div> + <div class="song-info-row" v-if="state.song.lyricist"> + <div class="song-info-label">浣滆瘝:</div> + <div class="song-info-value">{{ state.song.lyricist }}</div> + </div> + <div class="song-info-row" v-if="state.song.composer"> + <div class="song-info-label">浣滄洸:</div> + <div class="song-info-value">{{ state.song.composer }}</div> + </div> + <div class="song-info-row" v-if="state.song.language"> + <div class="song-info-label">姝屾洸璇:</div> + <div class="song-info-value">{{ state.song.language }}</div> + </div> + <div class="song-info-row" v-if="state.song.genre"> + <div class="song-info-label">姝屾洸娴佹淳:</div> + <div class="song-info-value">{{ state.song.genre }}</div> + </div> + <div class="song-info-row" v-if="state.song.recordCompany"> + <div class="song-info-label">鍞辩墖鍏徃:</div> + <div class="song-info-value">{{ state.song.recordCompany }}</div> + </div> + <div class="song-info-row" v-if="state.song.description"> + <div class="song-info-label">璇︾粏浠嬬粛:</div> + <div class="song-info-value">{{ state.song.description }}</div> + </div> </div> </div> </div> </div> - </div> </template> <style scoped lang="less"> @@ -405,27 +413,70 @@ const changeSortBy = (type) => { height: 100%; } .comment-wrapper { - min-height: 100%; + //min-height: 100%; width: 100%; background-attachment: fixed; position: relative; z-index: 1; transition: background-color ease 0.6s; + background-color: #121212; + height: calc(100vh - 160px); + overflow: hidden; + border-radius: 12px; +} + +.back-button { + position: relative; + margin: 24px 0 0 24px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 50%; + color: #fff; + transition: all 0.2s ease; +} + +.back-button:hover { + transform: scale(1.1); + background-color: rgba(0, 0, 0, .8); +} + +/* 鎻愮ず鏂囧瓧鏍峰紡 */ +.back-button[data-tooltip]:hover::after { + content: attr(data-tooltip); + position: absolute; + top: 38px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + white-space: nowrap; + z-index: 1000; + pointer-events: none; } .comment { height: 100%; width: 100%; margin: 0; - //position: fixed; - //transform: translateY(100%); - //background-color: @bgColor; + background: linear-gradient(to bottom, transparent 0%, rgba(0, 0, 0, 0.5) 100%); + overflow-y: auto; + max-height: calc(100vh - 160px); + border-radius: 12px; + + .comment-box { padding: 30px; display: flex; flex-wrap: wrap; flex-direction: column; - flex-flow: column; - height: 50%; + min-height: calc(100% - 24px); + padding-bottom: 30px; .info { display: flex; @@ -678,7 +729,7 @@ const changeSortBy = (type) => { display: flex; justify-content: center; align-items: center; - margin-top: 20px; + margin-top: 10px; } :deep(.el-pagination) { @@ -705,7 +756,7 @@ const changeSortBy = (type) => { margin-right: 30px; } - margin-bottom: 150px; + margin-bottom: 30px; width: 100%; padding: 20px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); @@ -774,4 +825,21 @@ const changeSortBy = (type) => { } } } + +.comment::-webkit-scrollbar { + width: 12px; +} + +.comment::-webkit-scrollbar-track { + background: transparent; +} + +.comment::-webkit-scrollbar-thumb { + background: #888; + border-radius: 10px; + + &:hover { + background: #555; + } +} </style> \ No newline at end of file diff --git a/src/components/MusicAlbumView.vue b/src/components/MusicAlbumView.vue index 3fafb4f..7d819f4 100644 --- a/src/components/MusicAlbumView.vue +++ b/src/components/MusicAlbumView.vue @@ -18,7 +18,7 @@ import { loadSongDurations } from '../utils/loadSongDurations'; const userToken = ref(JSON.parse(sessionStorage.getItem('user-token'))); const currentUserId = ref(userToken.value.id); -const emit = defineEmits(['pauseSong']); +const emit = defineEmits(['pauseSong', 'switchSongs', 'switchToArtist', 'back']); const props = defineProps({ albumInfo: { // 绫诲瀷 锛歩d, userid, title ,description ,picPath,createTime,updateTime,songNum type: Object, @@ -29,7 +29,7 @@ const props = defineProps({ required: true, }, musicList: {// 绫诲瀷 锛歩d ,title, artist, album,description, picPath,uploadTime - type: Object, + type: Array, required: true, }, playFromLeftBar: null, @@ -140,6 +140,10 @@ onMounted(() => { resizeObserver.value.observe(albumContent); } }) + + musicPlayIndex = props.currentSongId; + musicClickedIndex = props.currentSongId; + musicPauseIndex = props.isPaused ? props.currentSongId : null; }) onUnmounted(() => { @@ -150,7 +154,6 @@ onUnmounted(() => { }) const handelScroll = (event) => { - const playArea = document.querySelector(".play-area"); const fixedPlayArea = document.querySelector(".fixed-play-area"); const tipArea = document.querySelector(".tips"); @@ -215,11 +218,11 @@ const removeAlbum = (albumId) => { const playFromId = (musicId) => { if (musicId === null) { // 浠庡ご寮€濮嬫挱鏀� - musicPlayIndex.value = props.musicList[0].id; + musicPlayIndex = props.musicList[0].id; } else { - musicPlayIndex.value = musicId; + musicPlayIndex = musicId; } - emit('switchSongs', props.albumInfo, musicPlayIndex.value); + emit('switchSongs', props.albumInfo, musicPlayIndex); musicPauseIndex = null; } @@ -303,12 +306,22 @@ watch(() => props.currentSongId, (newId) => { musicClickedIndex = newId; musicPauseIndex = props.isPaused ? newId : null; } +}, { immediate: true }); +// 鍒ゆ柇褰撳墠鎾斁鐨勬瓕鏇叉槸鍚﹀湪姝屽崟涓� +const isCurrentSongInList = computed(() => { + if (!musicPlayIndex || !props.musicList) return false; + return props.musicList.some(song => song.id === musicPlayIndex); }); </script> <template> <div class="album-content" :style="{backgroundImage: gradientColor}" @mousewheel="handelScroll"> + <div class="back-button" data-tooltip="杩斿洖" @click="$emit('back')"> + <svg height="16" width="16" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.03.47a.75.75 0 0 1 0 1.06L4.56 8l6.47 6.47a.75.75 0 1 1-1.06 1.06L2.44 8 9.97.47a.75.75 0 0 1 1.06 0z"></path> + </svg> + </div> <div class="header"> <!-- .<img src="../assets/pictures/songs/2.jpg" alt="" class="album-image" @load="updateBackground"/>--> <img :src="albumInfo.picPath" alt="" class="album-image" @load="updateBackground(albumInfo.picPath)"/> @@ -330,10 +343,10 @@ watch(() => props.currentSongId, (newId) => { <div class="content"> <div class="play-area"> <div class="play-button"> - <play-button v-if="musicPlayIndex===null||musicPauseIndex!==null" + <play-button v-if="!isCurrentSongInList||musicPauseIndex!==null" @click="playFromId(musicPauseIndex)" style="position: absolute; top:20%;left:24%;color: #000000"/> - <pause-button v-if="musicPlayIndex!==null&&musicPauseIndex===null" + <pause-button v-if="isCurrentSongInList&&musicPauseIndex===null" @click="pauseMusic(musicPlayIndex)" style="position: absolute; top:24%;left:25%;color: #000000"/> </div> @@ -1308,4 +1321,39 @@ li:hover { .encore-text-marginal-bold { font-weight: 700; } + +.back-button { + position: relative; + margin: 24px 0 0 24px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 50%; + color: #fff; + transition: all 0.2s ease; + + &:hover { + transform: scale(1.1); + background-color: rgba(0, 0, 0, .8); + } +} + +.back-button[data-tooltip]:hover::after { + content: attr(data-tooltip); + position: absolute; + top: 38px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + white-space: nowrap; + z-index: 1000; + pointer-events: none; +} </style> diff --git a/src/components/SearchView.vue b/src/components/SearchView.vue index 48b585c..5bb9296 100644 --- a/src/components/SearchView.vue +++ b/src/components/SearchView.vue @@ -2,6 +2,8 @@ import {ref} from "vue"; import Empty from "./Empty.vue"; +const emit = defineEmits(['back']); + const {songResult, playlistResult} = defineProps({ songResult: Array, playlistResult: Array @@ -16,6 +18,12 @@ const handleTabClick = (tab) => { <template> <div class="search-view"> + <div class="back-button" data-tooltip="杩斿洖" @click="$emit('back')"> + <svg height="16" width="16" viewBox="0 0 16 16" fill="currentColor"> + <path d="M11.03.47a.75.75 0 0 1 0 1.06L4.56 8l6.47 6.47a.75.75 0 1 1-1.06 1.06L2.44 8 9.97.47a.75.75 0 0 1 1.06 0z"></path> + </svg> + </div> + <div class="tabs"> <button class="tab-button" @@ -65,10 +73,48 @@ const handleTabClick = (tab) => { <style scoped> .search-view { - padding: 20px; + padding: 0; +} + +.back-button { + position: relative; + margin: 24px 0 40px 24px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 50%; + color: #fff; + transition: all 0.2s ease; } +.back-button:hover { + transform: scale(1.1); + background-color: rgba(0, 0, 0, .8); +} + +/* 鎻愮ず鏂囧瓧鏍峰紡 */ +.back-button[data-tooltip]:hover::after { + content: attr(data-tooltip); + position: absolute; + top: 38px; + left: 50%; + transform: translateX(-50%); + background-color: #282828; + color: white; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + white-space: nowrap; + z-index: 1000; + pointer-events: none; +} + + .tabs { + margin-top: 20px; margin-bottom: 20px; display: flex; flex-direction: row; diff --git a/src/router/index.js b/src/router/index.js index bab1b4f..5a74422 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -39,13 +39,13 @@ const router = createRouter({ component: () => import('../views/ManagePage.vue'), meta: {title: 'Manage'} }, - { - path: '/test', - // @ts-ignore - component: () => import('../views/a.vue'), - meta: {title: 'test'} - - } + // { + // path: '/test', + // // @ts-ignore + // component: () => import('../views/a.vue'), + // meta: {title: 'test'} + // + // } ] }) diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue index de4d5bc..39f96c3 100644 --- a/src/views/HomePage.vue +++ b/src/views/HomePage.vue @@ -355,7 +355,7 @@ watch(volume, (newValue) => { volumePercentage.value = (newValue * 100) + '%'; }); const displayingSongs = ref([]); -const isPaused = ref(false); +const isPaused = ref(true); const duration = ref(0); const playingMode = ref(0); /* 0 - Normal, 1 - Loop, 2 - Random */ @@ -548,27 +548,42 @@ function receiveDataFromHome() { */ const midComponents = ref(0); const currentArtist = ref(null); +const backStack = ref([]); -const setMidComponents = (val, prop = null) => { - midComponents.value = val; - if(val === 1) - { - getPlaylistById({playlist_id:prop}).then((res) => { - displayingPlaylist.value = res.data.result; - getSongsByPlaylist({ - playlist_id: displayingPlaylist.value.id, - }).then((res) => { - displayingSongs.value = res.data.result; - }).catch(e => { - console.log("Failed to get songs!"); - }); - }) +const setMidComponents = (val, prop = null, isBack = false) => { + console.log("from" + midComponents.value + " to " + val) + if (val !== midComponents.value && !isBack) { + backStack.value.push(midComponents.value); } + + midComponents.value = val; + + // if(val === 1) { + // getPlaylistById({playlist_id:prop}).then((res) => { + // displayingPlaylist.value = res.data.result; + // getSongsByPlaylist({ + // playlist_id: displayingPlaylist.value.id, + // }).then((res) => { + // displayingSongs.value = res.data.result; + // }).catch(e => { + // console.log("Failed to get songs!"); + // }); + // }) + // } + if (val === 5) { currentArtist.value = prop; } +}; -} +const goBack = () => { + if (backStack.value.length > 0) { + const lastIndex = backStack.value.pop(); + setMidComponents(lastIndex, currentArtist.value, true); + } else { + setMidComponents(0, null); + } +}; /* share_icon @@ -682,7 +697,7 @@ const updateSongs = (newSongs) => { <MainView @openArtistView="(name) => setMidComponents(5, name)" @openEpisodeView="(name) => setMidComponents(4, name)" @openMusicView="" - @openAlbumView="(album) => setMidComponents(1, album)" + @openAlbumView="(album) => receiveDisplayingPlaylist(album)" /> </div> <!--height: 730px --> @@ -694,24 +709,19 @@ const updateSongs = (newSongs) => { @pauseSong="pauseCurrentSong" :playFromLeftBar="playFromLeftBarAlbum" :is-paused="isPaused" + @back="goBack" /> </div> <el-container v-if="midComponents === 2" class="playlist-container" - style="overflow: auto; height: 730px ;border-radius: 12px"> - <el-button class="exit-search" - data-tooltip="閫€鍑�" - - :class="{ 'adjusted-position': showRightContent }" - @click="setMidComponents(0)"></el-button> - <Comment :song-id=currentSongId :user-id=currentUserId></Comment> + style="overflow: scroll; height: 730px ;border-radius: 12px"> + <Comment :song-id=currentSongId :user-id=currentUserId + @back="goBack" + ></Comment> </el-container> <el-container v-if="midComponents === 3" class="playlist-container" style="overflow: auto; height: 730px ;border-radius: 12px"> - <el-button class="exit-search" - data-tooltip="閫€鍑�" - :class="{ 'adjusted-position': showRightContent }" - @click="setMidComponents(0)"></el-button> - <SearchView :songResult="songResult" :playlistResult="playlistResult"/> + <SearchView :songResult="songResult" :playlistResult="playlistResult" + @back="goBack"/> </el-container> <div v-if="midComponents === 4" class="playlist-container" style="overflow: scroll; border-radius: 12px"> @@ -725,7 +735,7 @@ const updateSongs = (newSongs) => { :current-song-id="currentSongId" @playSong="playArtistSong" @pauseSong="pauseCurrentSong" - @back="setMidComponents(1)" + @back="goBack" @updateSongs="updateSongs"/> </div> </div> -- GitLab