Files
vtsuru.live/src/views/view/SongListView.vue
2025-03-31 18:35:08 +08:00

208 lines
6.3 KiB
Vue

<template>
<NSpin
v-if="isLoading"
show
/>
<component
:is="selectedTemplate?.component"
v-else
ref="dynamicConfigRef"
:config="selectedTemplate?.settingName ? currentConfig : undefined"
:user-info="userInfo"
:bili-info="biliInfo"
:data="currentData"
:live-request-settings="settings"
:live-request-active="songsActive"
v-bind="$attrs"
@request-song="requestSong"
/>
<NButton
v-if="selectedTemplate?.settingName && userInfo?.id == accountInfo.id"
type="info"
size="small"
style="position: absolute; right: 32px; top: 20px; z-index: 1000; border: solid 3px #dfdfdf;"
@click="showSettingModal = true"
>
自定义
</NButton>
<NModal
v-model:show="showSettingModal"
style="max-width: 90vw; width: 800px;"
preset="card"
title="设置"
>
<DynamicForm
:name="selectedTemplate?.settingName"
:config-data="currentConfig"
:config="selectedTemplateConfig"
/>
</NModal>
</template>
<script lang="ts" setup>
import { DownloadConfig, useAccount } from '@/api/account';
import { Setting_LiveRequest, SongRequestInfo, SongsInfo, UserInfo } from '@/api/api-models';
import { QueryGetAPI, QueryPostAPIWithParams } from '@/api/query';
import { SONG_API_URL, SONG_REQUEST_API_URL, SongListTemplateMap } from '@/data/constants';
import { ConfigItemDefinition } from '@/data/VTsuruTypes';
import { useStorage } from '@vueuse/core';
import { addSeconds } from 'date-fns';
import { NButton, NModal, NSpin, useMessage } from 'naive-ui';
import { computed, onMounted, ref, watch } from 'vue';
const accountInfo = useAccount();
const nextRequestTime = useStorage('SongList.NextRequestTime', new Date());
const minRequestTime = 30;
const showSettingModal = ref(false);
const props = defineProps<{
biliInfo: any | undefined;
userInfo: UserInfo | undefined;
template?: string | undefined;
fakeData?: SongsInfo[];
}>();
const componentType = computed(() => {
return props.template ?? props.userInfo?.extra?.templateTypes['songlist']?.toLowerCase();
});
const currentData = ref<SongsInfo[]>();
const dynamicConfigRef = ref();
const selectedTemplateConfig = computed(() => {
if (dynamicConfigRef.value?.Config) {
return dynamicConfigRef.value?.Config as ConfigItemDefinition[];
}
return undefined;
});
const selectedTemplate = computed(() => {
if (componentType.value) {
return SongListTemplateMap[componentType.value];
}
return SongListTemplateMap[''];
});
const currentConfig = ref();
watch(
() => dynamicConfigRef,
() => {
getConfig();
},
);
const isLoading = ref(true);
const message = useMessage();
const errMessage = ref('');
const songsActive = ref<SongRequestInfo[]>([]);
const settings = ref<Setting_LiveRequest>({} as Setting_LiveRequest);
async function getSongRequestInfo() {
try {
const data = await QueryGetAPI<{ songs: SongRequestInfo[]; setting: Setting_LiveRequest; }>(
SONG_REQUEST_API_URL + 'get-active-and-settings',
{
id: props.userInfo?.id,
},
);
if (data.code == 200) {
return data.data;
}
} catch (err) { }
return {} as { songs: SongRequestInfo[]; setting: Setting_LiveRequest; };
}
async function getSongs() {
isLoading.value = true;
await QueryGetAPI<SongsInfo[]>(SONG_API_URL + 'get', {
id: props.userInfo?.id,
})
.then((data) => {
if (data.code == 200) {
currentData.value = data.data;
} else {
errMessage.value = data.message;
message.error('加载歌单失败: ' + data.message);
}
})
.catch((err) => {
message.error('加载失败: ' + err);
})
.finally(() => {
isLoading.value = false;
});
}
async function getConfig() {
if (!selectedTemplateConfig.value || !selectedTemplate.value!.settingName) return;
isLoading.value = true;
await DownloadConfig(selectedTemplate.value!.settingName, props.userInfo?.id)
.then((data) => {
if (data.msg) {
message.error('加载失败: ' + data.msg);
} else {
currentConfig.value = data.data;
}
})
.catch((err) => {
message.error('加载失败: ' + err);
})
.finally(() => {
isLoading.value = false;
});
}
async function requestSong(song: SongsInfo) {
if (song.options || !settings.value.allowFromWeb || (settings.value.allowFromWeb && !settings.value.allowAnonymousFromWeb)) {
navigator.clipboard.writeText(`${settings.value.orderPrefix} ${song.name}`);
if (!settings.value.allowAnonymousFromWeb) {
message.warning('主播不允许匿名点歌, 需要从网页点歌的话请注册登录, 点歌弹幕已复制到剪切板');
}
else if (!accountInfo.value.id) {
message.warning('要从网页点歌请先登录, 点歌弹幕已复制到剪切板');
} else {
message.success('复制成功');
}
} else {
if (props.userInfo) {
if (!accountInfo.value.id && nextRequestTime.value > new Date()) {
message.warning('距离点歌冷却还有' + (nextRequestTime.value.getTime() - new Date().getTime()) / 1000 + '秒');
return;
}
try {
const data = await QueryPostAPIWithParams(SONG_REQUEST_API_URL + 'add-from-web', {
target: props.userInfo?.id,
song: song.key,
});
if (data.code == 200) {
message.success('点歌成功');
nextRequestTime.value = addSeconds(new Date(), minRequestTime);
} else {
message.error('点歌失败: ' + data.message);
}
} catch (err) {
message.error('点歌失败: ' + err);
}
}
}
}
onMounted(async () => {
if (!props.fakeData) {
try {
await getSongs();
setTimeout(async () => {
const r = await getSongRequestInfo();
if (r) {
songsActive.value = r.songs;
settings.value = r.setting;
}
await getConfig();
}, 300);
} catch (err) {
message.error('加载失败: ' + err);
console.error(err);
}
} else {
currentData.value = props.fakeData;
isLoading.value = false;
}
});
</script>