From eb8df943e39404f0b2b41f8ee1b389772e9aab54 Mon Sep 17 00:00:00 2001 From: Megghy Date: Wed, 18 Oct 2023 21:28:55 +0800 Subject: [PATCH] 1018 --- src/components/SongList.vue | 114 ++++++++++++++++--- src/views/ManageLayout.vue | 2 +- src/views/manage/HistoryView.vue | 188 +++++++++++++++++++++++++++++-- src/views/manage/LotteryView.vue | 1 - 4 files changed, 274 insertions(+), 31 deletions(-) diff --git a/src/components/SongList.vue b/src/components/SongList.vue index 4c505a7..516754b 100644 --- a/src/components/SongList.vue +++ b/src/components/SongList.vue @@ -2,7 +2,7 @@ import { SongAuthorInfo, SongFrom, SongLanguage, SongsInfo, UserInfo } from '@/api/api-models' import { QueryGetAPI, QueryPostAPI } from '@/api/query' import { SONG_API_URL } from '@/data/constants' -import { refDebounced, useDebounceFn } from '@vueuse/core' +import { refDebounced, useDebounceFn, useLocalStorage } from '@vueuse/core' import { List } from 'linqts' import { DataTableBaseColumn, @@ -51,6 +51,7 @@ watch( }, 1) } ) +const volume = useLocalStorage('Settings.AplayerVolume', 0.8) const songsInternal = ref(props.songs) const songsComputed = computed(() => { if (debouncedInput.value) { @@ -70,7 +71,7 @@ const aplayerMusic = ref<{ title: string artist: string src: string - pic: string + lrc: string }>() const formRef = ref(null) @@ -150,10 +151,9 @@ const authorColumn = ref>({ }, }) const onAuthorClick = (author: string) => { - if(authorColumn.value.filterOptionValue == author){ + if (authorColumn.value.filterOptionValue == author) { authorColumn.value.filterOptionValue = undefined - } - else { + } else { authorColumn.value.filterOptionValue = author } } @@ -218,11 +218,11 @@ function createColumns(): DataTableColumns { NSpace, { justify: 'end', - size: 10 + size: 10, }, () => [ GetPlayButton(data), - data.url + data.url?.endsWith('mp3') || data.url?.endsWith('flac') || data.url?.endsWith('ogg') || data.url?.endsWith('wav') || data.url?.endsWith('m4a') ? h(NTooltip, null, { trigger: () => h( @@ -231,14 +231,7 @@ function createColumns(): DataTableColumns { type: 'primary', size: 'small', circle: true, - onClick: () => { - aplayerMusic.value = { - title: data.name, - artist: data.author.join('/') ?? '', - src: data.url, - pic: '', - } - }, + onClick: () => OnPlayMusic(data), }, { icon: () => h(NIcon, { component: Play24Filled }), @@ -301,6 +294,87 @@ function createColumns(): DataTableColumns { }, ] } +function OnPlayMusic(song: SongsInfo) { + aplayerMusic.value = undefined + if (song.from == SongFrom.Netease) GetLyric(song) + else { + aplayerMusic.value = { + title: song.name, + artist: song.author.join('/') ?? '', + src: song.url, + lrc: '', + } + } +} +async function GetLyric(song: SongsInfo) { + QueryGetAPI<{ lyric: string; tlyric: string }>(SONG_API_URL + 'get-netease-lyric', { id: song.id }) + .then((data) => { + console.log(mergeLyrics(data.data.lyric, data.data.tlyric)) + if (data.code == 200) { + aplayerMusic.value = { + title: song.name, + artist: song.author.join('/') ?? '', + src: song.url, + lrc: data.data.tlyric ? mergeLyrics(data.data.lyric, data.data.tlyric) : data.data.lyric, + } + //aplayerMusic.value.lrc = data.data.lyric + } + }) + .catch((err) => { + console.error(err) + aplayerMusic.value = { + title: song.name, + artist: song.author.join('/') ?? '', + src: song.url, + lrc: '', + } + }) +} +function mergeLyrics(originalLyrics: string, translatedLyrics: string): string { + const originalLines = originalLyrics.split('\n') + const translatedLines = translatedLyrics.split('\n') + + let mergedLyrics = '' + + for (let i = 0; i < originalLines.length; i++) { + const originalLine = originalLines[i]?.trim() + const originalTimeMatch = originalLine?.match(/\[(\d{2}:\d{2}\.\d{2,3})\]/) // 匹配原歌词的时间字符串 + + let mergedLine = originalLine + + if (originalTimeMatch) { + const originalTime = originalTimeMatch[1] + const translatedLineIndex = translatedLines.findIndex((line) => line.includes(originalTime)) + + if (translatedLineIndex !== -1) { + const translatedLine = translatedLines[translatedLineIndex] + const translatedTimeMatch = translatedLine.match(/\[(\d{2}:\d{2}\.\d{2,3})\]/) // 匹配翻译歌词的时间字符串 + + if (translatedTimeMatch && translatedTimeMatch[1] === originalTime) { + const translatedText = translatedLine.slice(translatedTimeMatch[0].length).trim() + if (translatedText) { + mergedLine += ` (${translatedText})` + } + translatedLines.splice(translatedLineIndex, 1) // 从翻译歌词数组中移除已匹配的行 + } + } + } + if (!mergedLine.match(/^\[(\d{2}:\d{2}\.\d{2,3})\]$/)) { + //不是空行 + mergedLyrics += `${mergedLine}\n` + } + } + + // 将剩余的非空翻译歌词单独放在一行 + for (const translatedLine of translatedLines) { + const translatedText = translatedLine.trim() + if (translatedText) { + mergedLyrics += `${translatedText}\n` + } + } + + return mergedLyrics.trim() +} function GetPlayButton(song: SongsInfo) { switch (song.from) { case SongFrom.FiveSing: { @@ -411,12 +485,16 @@ onMounted(() => { - 回到主页 + 回到主页 diff --git a/src/views/manage/HistoryView.vue b/src/views/manage/HistoryView.vue index 25f5144..48177e3 100644 --- a/src/views/manage/HistoryView.vue +++ b/src/views/manage/HistoryView.vue @@ -18,8 +18,11 @@ const message = useMessage() const fansHistory = ref<{ time: number; count: number }[]>() const guardHistory = ref<{ time: number; count: number }[]>() +const upstatHistory = ref<{ time: number; stats: { views: number; likes: number } }[]>() const fansOption = ref() const guardsOption = ref() +const upstatViewOption = ref() +const upstatLikeOption = ref() async function getFansHistory() { await QueryGetAPI< @@ -27,9 +30,7 @@ async function getFansHistory() { time: number count: number }[] - >(HISTORY_API_URL + 'fans', { - id: accountInfo.value?.id, - }) + >(HISTORY_API_URL + 'fans') .then((data) => { if (data.code == 200) { fansHistory.value = data.data @@ -48,9 +49,7 @@ async function getGuardsHistory() { time: number count: number }[] - >(HISTORY_API_URL + 'guards', { - id: accountInfo.value?.id, - }) + >(HISTORY_API_URL + 'guards') .then((data) => { if (data.code == 200) { guardHistory.value = data.data @@ -63,6 +62,28 @@ async function getGuardsHistory() { message.error('加载失败') }) } +async function getUpstatHistory() { + await QueryGetAPI< + { + time: number + stats: { + views: number + likes: number + } + }[] + >(HISTORY_API_URL + 'upstat') + .then((data) => { + if (data.code == 200) { + upstatHistory.value = data.data + } else { + message.error('加载失败: ' + data.message) + } + }) + .catch((err) => { + console.error(err) + message.error('加载失败') + }) +} function isSameDay(time1: number, time2: number) { const time1Date = new Date(time1) const time2Date = new Date(time2) @@ -100,6 +121,25 @@ function getOptions() { lastDayGuards = g.count } }) + let upstatViewIncreace: { time: number; value: number }[] = [] + let upstatLikeIncreace: { time: number; value: number }[] = [] + if (upstatHistory.value && upstatHistory.value.length > 0) { + let lastUpstatView = upstatHistory.value[0].stats.views + let lastUpstatLike = upstatHistory.value[0].stats.likes + + upstatHistory.value?.forEach((u) => { + upstatViewIncreace.push({ + time: u.time, + value: u.stats.views - lastUpstatView, + }) + lastUpstatView = u.stats.views + upstatLikeIncreace.push({ + time: u.time, + value: u.stats.likes - lastUpstatLike, + }) + lastUpstatLike = u.stats.likes + }) + } fansOption.value = { title: { @@ -152,8 +192,6 @@ function getOptions() { { name: '粉丝数', type: 'line', - xAxisIndex: 1, - yAxisIndex: 1, emphasis: { focus: 'series', }, @@ -162,6 +200,7 @@ function getOptions() { { name: '增量 /日', type: 'line', + yAxisIndex: 1, smooth: true, showSymbol: false, emphasis: { @@ -193,9 +232,6 @@ function getOptions() { { type: 'value', }, - { - type: 'value', - }, ], xAxis: [ { @@ -234,11 +270,139 @@ function getOptions() { }, ], } + upstatViewOption.value = { + title: { + text: '投稿播放数', + left: 'left', + }, + tooltip: { + trigger: 'axis', + }, + legend: {}, + yAxis: [ + { + type: 'value', + }, + { + type: 'value', + }, + ], + xAxis: [ + { + type: 'category', + axisTick: { + alignWithLabel: true, + }, + axisLine: { + onZero: false, + lineStyle: { + color: '#EE6666', + }, + }, + // prettier-ignore + data: upstatHistory.value?.map((f) => format(f.time, 'yyyy-MM-dd')), + }, + ], + series: [ + { + name: '播放数', + type: 'line', + emphasis: { + focus: 'series', + }, + data: upstatHistory.value?.map((f) => f.stats.views), + }, + { + name: '日增', + type: 'line', + step: 'start', + yAxisIndex: 1, + emphasis: { + focus: 'series', + }, + data: upstatViewIncreace.map((f) => f.value), + }, + ], + dataZoom: [ + { + show: true, + realtime: true, + start: 0, + end: 100, + xAxisIndex: [0, 1], + }, + ], + } + upstatLikeOption.value = { + title: { + text: '投稿点赞数', + left: 'left', + }, + tooltip: { + trigger: 'axis', + }, + legend: {}, + yAxis: [ + { + type: 'value', + }, + { + type: 'value', + }, + ], + xAxis: [ + { + type: 'category', + axisTick: { + alignWithLabel: true, + }, + axisLine: { + onZero: false, + lineStyle: { + color: '#EE6666', + }, + }, + // prettier-ignore + data: upstatHistory.value?.map((f) => format(f.time, 'yyyy-MM-dd')), + }, + ], + series: [ + { + name: '点赞数', + type: 'line', + emphasis: { + focus: 'series', + }, + data: upstatHistory.value?.map((f) => f.stats.likes), + }, + { + name: '日增', + type: 'line', + yAxisIndex: 1, + step: 'start', + + emphasis: { + focus: 'series', + }, + data: upstatLikeIncreace.map((f) => f.value), + }, + ], + dataZoom: [ + { + show: true, + realtime: true, + start: 0, + end: 100, + xAxisIndex: [0, 1], + }, + ], + } } onMounted(async () => { await getFansHistory() await getGuardsHistory() + await getUpstatHistory() getOptions() }) @@ -247,5 +411,7 @@ onMounted(async () => { + + diff --git a/src/views/manage/LotteryView.vue b/src/views/manage/LotteryView.vue index beb8c0f..2e5efeb 100644 --- a/src/views/manage/LotteryView.vue +++ b/src/views/manage/LotteryView.vue @@ -284,7 +284,6 @@ function reset() { switch (currentType.value) { case 'comment': { commentUsers.value = JSON.parse(JSON.stringify(originCommentUsers.value)) - console.log(originCommentUsers.value) break } case 'forward': {