mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-10 20:36:55 +08:00
重构多个组件以优化代码格式和可读性,删除不必要的文件,更新类型定义,添加数据分析路由
This commit is contained in:
@@ -797,49 +797,88 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NAlert :type="accountInfo.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? 'success' : 'warning'"
|
||||
v-if="accountInfo.id">
|
||||
<NAlert
|
||||
v-if="accountInfo.id"
|
||||
:type="accountInfo.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? 'success' : 'warning'"
|
||||
>
|
||||
启用弹幕点播功能
|
||||
<NSwitch :value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.SongRequest)"
|
||||
@update:value="onUpdateFunctionEnable" />
|
||||
<NSwitch
|
||||
:value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.SongRequest)"
|
||||
@update:value="onUpdateFunctionEnable"
|
||||
/>
|
||||
|
||||
<br />
|
||||
<br>
|
||||
<NText depth="3">
|
||||
如果没有部署
|
||||
<NButton text type="primary" tag="a" href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs" target="_blank">
|
||||
<NButton
|
||||
text
|
||||
type="primary"
|
||||
tag="a"
|
||||
href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs"
|
||||
target="_blank"
|
||||
>
|
||||
VtsuruEventFetcher
|
||||
</NButton>
|
||||
则其需要保持此页面开启才能点播, 也不要同时开多个页面, 会导致点播重复 !(部署了则不影响)
|
||||
</NText>
|
||||
</NAlert>
|
||||
<NAlert type="warning" v-else title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑">
|
||||
<NButton tag="a" href="/manage" target="_blank" type="primary"> 前往登录或注册 </NButton>
|
||||
<NAlert
|
||||
v-else
|
||||
type="warning"
|
||||
title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑"
|
||||
>
|
||||
<NButton
|
||||
tag="a"
|
||||
href="/manage"
|
||||
target="_blank"
|
||||
type="primary"
|
||||
>
|
||||
前往登录或注册
|
||||
</NButton>
|
||||
</NAlert>
|
||||
<br />
|
||||
<br>
|
||||
<NCard size="small">
|
||||
<NSpace align="center">
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton @click="showOBSModal = true" type="primary" :disabled="!accountInfo"> OBS 组件 </NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
:disabled="!accountInfo"
|
||||
@click="showOBSModal = true"
|
||||
>
|
||||
OBS 组件
|
||||
</NButton>
|
||||
</template>
|
||||
{{ configCanEdit ? '' : '登陆后才可以使用此功能' }}
|
||||
</NTooltip>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<br />
|
||||
<br>
|
||||
<NCard>
|
||||
<NTabs v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.SongRequest)" animated
|
||||
display-directive="show:lazy">
|
||||
<NTabPane name="list" tab="列表">
|
||||
<NTabs
|
||||
v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.SongRequest)"
|
||||
animated
|
||||
display-directive="show:lazy"
|
||||
>
|
||||
<NTabPane
|
||||
name="list"
|
||||
tab="列表"
|
||||
>
|
||||
<NCard size="small">
|
||||
<NSpace align="center">
|
||||
<NTag type="success" :bordered="false">
|
||||
<NTag
|
||||
type="success"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="PeopleQueue24Filled" />
|
||||
</template>
|
||||
队列 | {{activeSongs.filter((s) => s.status == SongRequestStatus.Waiting).length}}
|
||||
队列 | {{ activeSongs.filter((s) => s.status == SongRequestStatus.Waiting).length }}
|
||||
</NTag>
|
||||
<NTag type="success" :bordered="false">
|
||||
<NTag
|
||||
type="success"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Checkmark12Regular" />
|
||||
</template>
|
||||
@@ -851,23 +890,54 @@ onUnmounted(() => {
|
||||
个
|
||||
</NTag>
|
||||
<NInputGroup>
|
||||
<NInput placeholder="手动添加" v-model:value="newSongName" />
|
||||
<NButton type="primary" @click="addSongManual"> 添加 </NButton>
|
||||
<NInput
|
||||
v-model:value="newSongName"
|
||||
placeholder="手动添加"
|
||||
/>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="addSongManual"
|
||||
>
|
||||
添加
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NRadioGroup v-model:value="settings.sortType" :disabled="!configCanEdit" @update:value="updateSettings"
|
||||
type="button">
|
||||
<NRadioButton :value="QueueSortType.TimeFirst"> 加入时间优先 </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.PaymentFist"> 付费价格优先 </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.GuardFirst"> 舰长优先 (按等级) </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.FansMedalFirst"> 粉丝牌等级优先 </NRadioButton>
|
||||
<NRadioGroup
|
||||
v-model:value="settings.sortType"
|
||||
:disabled="!configCanEdit"
|
||||
type="button"
|
||||
@update:value="updateSettings"
|
||||
>
|
||||
<NRadioButton :value="QueueSortType.TimeFirst">
|
||||
加入时间优先
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.PaymentFist">
|
||||
付费价格优先
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.GuardFirst">
|
||||
舰长优先 (按等级)
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.FansMedalFirst">
|
||||
粉丝牌等级优先
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-if="configCanEdit"
|
||||
v-model:checked="settings.isReverse"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
倒序
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-else
|
||||
v-model:checked="isReverse"
|
||||
>
|
||||
倒序
|
||||
</NCheckbox>
|
||||
<NCheckbox v-else v-model:checked="isReverse"> 倒序 </NCheckbox>
|
||||
<NPopconfirm @positive-click="deactiveAllSongs">
|
||||
<template #trigger>
|
||||
<NButton type="error"> 全部取消 </NButton>
|
||||
<NButton type="error">
|
||||
全部取消
|
||||
</NButton>
|
||||
</template>
|
||||
确定全部取消吗?
|
||||
</NPopconfirm>
|
||||
@@ -875,31 +945,68 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
<NDivider> 共 {{ activeSongs.length }} 首 </NDivider>
|
||||
<Transition>
|
||||
<div v-if="selectedSong" class="song-list">
|
||||
<SongPlayer :song="selectedSong" v-model:is-lrc-loading="isLrcLoading" />
|
||||
<div
|
||||
v-if="selectedSong"
|
||||
class="song-list"
|
||||
>
|
||||
<SongPlayer
|
||||
v-model:is-lrc-loading="isLrcLoading"
|
||||
:song="selectedSong"
|
||||
/>
|
||||
<NDivider style="margin: 15px 0 15px 0" />
|
||||
</div>
|
||||
</Transition>
|
||||
<NList v-if="activeSongs.length > 0" :show-divider="false" hoverable>
|
||||
<NListItem v-for="song in activeSongs" :key="song.id" style="padding: 5px">
|
||||
<NCard embedded size="small" content-style="padding: 5px;"
|
||||
:style="`${song.status == SongRequestStatus.Singing ? 'animation: animated-border 2.5s infinite;' : ''};height: 100%;`">
|
||||
<NSpace justify="space-between" align="center" style="height: 100%; margin: 0 5px 0 5px">
|
||||
<NList
|
||||
v-if="activeSongs.length > 0"
|
||||
:show-divider="false"
|
||||
hoverable
|
||||
>
|
||||
<NListItem
|
||||
v-for="song in activeSongs"
|
||||
:key="song.id"
|
||||
style="padding: 5px"
|
||||
>
|
||||
<NCard
|
||||
embedded
|
||||
size="small"
|
||||
content-style="padding: 5px;"
|
||||
:style="`${song.status == SongRequestStatus.Singing ? 'animation: animated-border 2.5s infinite;' : ''};height: 100%;`"
|
||||
>
|
||||
<NSpace
|
||||
justify="space-between"
|
||||
align="center"
|
||||
style="height: 100%; margin: 0 5px 0 5px"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<div
|
||||
:style="`border-radius: 4px; background-color: ${song.status == SongRequestStatus.Singing ? '#75c37f' : '#577fb8'}; width: 10px; height: 20px`">
|
||||
</div>
|
||||
<NText strong style="font-size: 18px">
|
||||
:style="`border-radius: 4px; background-color: ${song.status == SongRequestStatus.Singing ? '#75c37f' : '#577fb8'}; width: 10px; height: 20px`"
|
||||
/>
|
||||
<NText
|
||||
strong
|
||||
style="font-size: 18px"
|
||||
>
|
||||
{{ song.songName }}
|
||||
</NText>
|
||||
<template v-if="song.from == SongRequestFrom.Manual">
|
||||
<NTag size="small" :bordered="false"> 手动添加 </NTag>
|
||||
<NTag
|
||||
size="small"
|
||||
:bordered="false"
|
||||
>
|
||||
手动添加
|
||||
</NTag>
|
||||
</template>
|
||||
<template v-else>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NTag size="small" :bordered="false" type="info">
|
||||
<NText italic depth="3">
|
||||
<NTag
|
||||
size="small"
|
||||
:bordered="false"
|
||||
type="info"
|
||||
>
|
||||
<NText
|
||||
italic
|
||||
depth="3"
|
||||
>
|
||||
{{ song.user?.name }}
|
||||
</NText>
|
||||
</NTag>
|
||||
@@ -907,12 +1014,21 @@ onUnmounted(() => {
|
||||
{{ song.user?.uid }}
|
||||
</NTooltip>
|
||||
</template>
|
||||
<NSpace v-if="
|
||||
(song.from == SongRequestFrom.Danmaku || song.from == SongRequestFrom.SC) &&
|
||||
song.user?.fans_medal_wearing_status
|
||||
">
|
||||
<NTag size="tiny" round>
|
||||
<NTag size="tiny" round :bordered="false">
|
||||
<NSpace
|
||||
v-if="
|
||||
(song.from == SongRequestFrom.Danmaku || song.from == SongRequestFrom.SC) &&
|
||||
song.user?.fans_medal_wearing_status
|
||||
"
|
||||
>
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
>
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
:bordered="false"
|
||||
>
|
||||
<NText depth="3">
|
||||
{{ song.user?.fans_medal_level }}
|
||||
</NText>
|
||||
@@ -922,32 +1038,54 @@ onUnmounted(() => {
|
||||
</span>
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<NTag v-if="(song.user?.guard_level ?? 0) > 0" size="small" :bordered="false"
|
||||
:color="{ textColor: 'white', color: GetGuardColor(song.user?.guard_level) }">
|
||||
<NTag
|
||||
v-if="(song.user?.guard_level ?? 0) > 0"
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:color="{ textColor: 'white', color: GetGuardColor(song.user?.guard_level) }"
|
||||
>
|
||||
{{ song.user?.guard_level == 1 ? '总督' : song.user?.guard_level == 2 ? '提督' : '舰长' }}
|
||||
</NTag>
|
||||
<NTag v-if="song.from == SongRequestFrom.SC" size="small"
|
||||
:color="{ textColor: 'white', color: GetSCColor(song.price ?? 0) }">
|
||||
<NTag
|
||||
v-if="song.from == SongRequestFrom.SC"
|
||||
size="small"
|
||||
:color="{ textColor: 'white', color: GetSCColor(song.price ?? 0) }"
|
||||
>
|
||||
SC | {{ song.price }}
|
||||
</NTag>
|
||||
<NTag v-if="song.from == SongRequestFrom.Gift" size="small"
|
||||
:color="{ textColor: 'white', color: GetSCColor(song.price ?? 0) }">
|
||||
<NTag
|
||||
v-if="song.from == SongRequestFrom.Gift"
|
||||
size="small"
|
||||
:color="{ textColor: 'white', color: GetSCColor(song.price ?? 0) }"
|
||||
>
|
||||
Gift | {{ song.price }}
|
||||
</NTag>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText style="font-size: small">
|
||||
<NTime :time="song.createAt" type="relative" :key="updateKey" />
|
||||
<NTime
|
||||
:key="updateKey"
|
||||
:time="song.createAt"
|
||||
type="relative"
|
||||
/>
|
||||
</NText>
|
||||
</template>
|
||||
<NTime :time="song.createAt" />
|
||||
</NTooltip>
|
||||
</NSpace>
|
||||
<NSpace justify="end" align="center">
|
||||
<NSpace
|
||||
justify="end"
|
||||
align="center"
|
||||
>
|
||||
<NTooltip v-if="song.song?.url">
|
||||
<template #trigger>
|
||||
<NButton circle type="success" style="height: 30px; width: 30px"
|
||||
:loading="isLrcLoading == song?.song?.key" @click="selectedSong = song.song">
|
||||
<NButton
|
||||
circle
|
||||
type="success"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLrcLoading == song?.song?.key"
|
||||
@click="selectedSong = song.song"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Play24Filled" />
|
||||
</template>
|
||||
@@ -957,17 +1095,24 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="primary" style="height: 30px; width: 30px" :disabled="songs.findIndex((s) => s.id != song.id && s.status == SongRequestStatus.Singing) > -1
|
||||
" @click="
|
||||
<NButton
|
||||
circle
|
||||
type="primary"
|
||||
style="height: 30px; width: 30px"
|
||||
:disabled="songs.findIndex((s) => s.id != song.id && s.status == SongRequestStatus.Singing) > -1
|
||||
"
|
||||
:style="`animation: ${song.status == SongRequestStatus.Waiting ? '' : 'loading 5s linear infinite'}`"
|
||||
:secondary="song.status == SongRequestStatus.Singing"
|
||||
:loading="isLoading"
|
||||
@click="
|
||||
updateSongStatus(
|
||||
song,
|
||||
song.status == SongRequestStatus.Singing
|
||||
? SongRequestStatus.Waiting
|
||||
: SongRequestStatus.Singing,
|
||||
)
|
||||
"
|
||||
:style="`animation: ${song.status == SongRequestStatus.Waiting ? '' : 'loading 5s linear infinite'}`"
|
||||
:secondary="song.status == SongRequestStatus.Singing" :loading="isLoading">
|
||||
"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Mic24Filled" />
|
||||
</template>
|
||||
@@ -983,8 +1128,13 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="success" style="height: 30px; width: 30px" :loading="isLoading"
|
||||
@click="updateSongStatus(song, SongRequestStatus.Finish)">
|
||||
<NButton
|
||||
circle
|
||||
type="success"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
@click="updateSongStatus(song, SongRequestStatus.Finish)"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Checkmark12Regular" />
|
||||
</template>
|
||||
@@ -996,7 +1146,12 @@ onUnmounted(() => {
|
||||
<template #trigger>
|
||||
<NPopconfirm @positive-click="blockUser(song)">
|
||||
<template #trigger>
|
||||
<NButton circle type="warning" style="height: 30px; width: 30px" :loading="isLoading">
|
||||
<NButton
|
||||
circle
|
||||
type="warning"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="PresenceBlocked16Regular" />
|
||||
</template>
|
||||
@@ -1009,8 +1164,13 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="error" style="height: 30px; width: 30px" :loading="isLoading"
|
||||
@click="updateSongStatus(song, SongRequestStatus.Cancel)">
|
||||
<NButton
|
||||
circle
|
||||
type="error"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
@click="updateSongStatus(song, SongRequestStatus.Cancel)"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Dismiss16Filled" />
|
||||
</template>
|
||||
@@ -1023,39 +1183,64 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
</NListItem>
|
||||
</NList>
|
||||
<NEmpty v-else description="暂无曲目" />
|
||||
<NEmpty
|
||||
v-else
|
||||
description="暂无曲目"
|
||||
/>
|
||||
</NTabPane>
|
||||
<NTabPane name="history" tab="历史">
|
||||
<NTabPane
|
||||
name="history"
|
||||
tab="历史"
|
||||
>
|
||||
<NCard size="small">
|
||||
<NSpace>
|
||||
<NInputGroup style="width: 300px">
|
||||
<NInputGroupLabel> 筛选曲名 </NInputGroupLabel>
|
||||
<NInput v-model:value="filterSongName" clearable>
|
||||
<NInput
|
||||
v-model:value="filterSongName"
|
||||
clearable
|
||||
>
|
||||
<template #suffix>
|
||||
<NCheckbox v-model:checked="filterSongNameContains"> 包含 </NCheckbox>
|
||||
<NCheckbox v-model:checked="filterSongNameContains">
|
||||
包含
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NInput>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 300px">
|
||||
<NInputGroupLabel> 筛选用户 </NInputGroupLabel>
|
||||
<NInput v-model:value="filterName" clearable>
|
||||
<NInput
|
||||
v-model:value="filterName"
|
||||
clearable
|
||||
>
|
||||
<template #suffix>
|
||||
<NCheckbox v-model:checked="filterNameContains"> 包含 </NCheckbox>
|
||||
<NCheckbox v-model:checked="filterNameContains">
|
||||
包含
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NInput>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NDataTable size="small" ref="table" :columns="columns" :data="songs" :pagination="{
|
||||
itemCount: songs.length,
|
||||
pageSizes: [20, 50, 100],
|
||||
showSizePicker: true,
|
||||
prefix({ itemCount }) {
|
||||
return `共 ${itemCount} 条记录`
|
||||
},
|
||||
}" />
|
||||
<NDataTable
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="columns"
|
||||
:data="songs"
|
||||
:pagination="{
|
||||
itemCount: songs.length,
|
||||
pageSizes: [20, 50, 100],
|
||||
showSizePicker: true,
|
||||
prefix({ itemCount }) {
|
||||
return `共 ${itemCount} 条记录`
|
||||
},
|
||||
}"
|
||||
/>
|
||||
</NTabPane>
|
||||
<NTabPane name="setting" tab="设置">
|
||||
<NTabPane
|
||||
name="setting"
|
||||
tab="设置"
|
||||
>
|
||||
<NSpin :show="isLoading">
|
||||
<NDivider> 规则 </NDivider>
|
||||
<NSpace vertical>
|
||||
@@ -1064,57 +1249,119 @@ onUnmounted(() => {
|
||||
<NInputGroupLabel> 点播弹幕前缀 </NInputGroupLabel>
|
||||
<template v-if="configCanEdit">
|
||||
<NInput v-model:value="settings.orderPrefix" />
|
||||
<NButton @click="updateSettings" type="primary">确定</NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</template>
|
||||
<NInput v-else v-model:value="defaultPrefix" />
|
||||
<NInput
|
||||
v-else
|
||||
v-model:value="defaultPrefix"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NAlert v-if="settings.orderPrefix.includes(' ')" type="info"> 前缀包含空格 </NAlert>
|
||||
<NAlert
|
||||
v-if="settings.orderPrefix.includes(' ')"
|
||||
type="info"
|
||||
>
|
||||
前缀包含空格
|
||||
</NAlert>
|
||||
</NSpace>
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 最大队列长度 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.queueMaxSize" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.queueMaxSize"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.enableOnStreaming" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableOnStreaming"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
仅在直播时才允许加入
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowAllDanmaku" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowAllDanmaku"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许所有弹幕点播
|
||||
</NCheckbox>
|
||||
<template v-if="!settings.allowAllDanmaku">
|
||||
<NCheckbox v-model:checked="settings.needWearFanMedal" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.needWearFanMedal"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
需要拥有粉丝牌
|
||||
</NCheckbox>
|
||||
<NInputGroup v-if="settings.needWearFanMedal" style="width: 250px">
|
||||
<NInputGroup
|
||||
v-if="settings.needWearFanMedal"
|
||||
style="width: 250px"
|
||||
>
|
||||
<NInputGroupLabel> 最低粉丝牌等级 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.fanMedalMinLevel" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.fanMedalMinLevel"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needJianzhang"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needJianzhang"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
只允许舰长
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needTidu"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needTidu"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
只允许提督
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needZongdu"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needZongdu"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
只允许总督
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NSpace>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.allowSC" @update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowSC"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许通过 SuperChat 点播
|
||||
</NCheckbox>
|
||||
<span v-if="settings.allowSC">
|
||||
<NCheckbox v-model:checked="settings.allowSC" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowSC"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
SC 点播无视限制
|
||||
</NCheckbox>
|
||||
<NTooltip>
|
||||
@@ -1124,10 +1371,22 @@ onUnmounted(() => {
|
||||
包含冷却时间, 队列长度, 重复点播等
|
||||
</NTooltip>
|
||||
</span>
|
||||
<NInputGroup v-if="settings.allowSC" style="width: 250px">
|
||||
<NInputGroup
|
||||
v-if="settings.allowSC"
|
||||
style="width: 250px"
|
||||
>
|
||||
<NInputGroupLabel> 最低SC价格 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.scMinPrice" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.scMinPrice"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
|
||||
@@ -1193,46 +1452,103 @@ onUnmounted(() => {
|
||||
</NSpace> -->
|
||||
<NDivider> 点歌 </NDivider>
|
||||
<NSpace>
|
||||
<NCheckbox v-model:checked="settings.onlyAllowSongList" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.onlyAllowSongList"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
仅允许点
|
||||
<NButton text tag="a" href="/manage/song-list" target="_blank" type="info"> 歌单 </NButton>
|
||||
<NButton
|
||||
text
|
||||
tag="a"
|
||||
href="/manage/song-list"
|
||||
target="_blank"
|
||||
type="info"
|
||||
>
|
||||
歌单
|
||||
</NButton>
|
||||
内的歌曲
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowFromWeb" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowFromWeb"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许通过网页点歌
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="settings.allowFromWeb" v-model:checked="settings.allowAnonymousFromWeb" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="settings.allowFromWeb"
|
||||
v-model:checked="settings.allowAnonymousFromWeb"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许匿名通过网页点歌
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 冷却 (单位: 秒) </NDivider>
|
||||
<NCheckbox v-model:checked="settings.enableCooldown" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableCooldown"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
启用点播冷却
|
||||
</NCheckbox>
|
||||
<NSpace v-if="settings.enableCooldown">
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 普通弹幕 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.cooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.cooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 舰长 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.jianzhangCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.jianzhangCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 提督 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.tiduCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.tiduCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 总督 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.zongduCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.zongduCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NDivider> OBS </NDivider>
|
||||
@@ -1240,40 +1556,74 @@ onUnmounted(() => {
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 标题 </NInputGroupLabel>
|
||||
<template v-if="configCanEdit">
|
||||
<NInput v-model:value="settings.obsTitle" placeholder="默认为 点播" />
|
||||
<NButton @click="updateSettings" type="primary">确定</NButton>
|
||||
<NInput
|
||||
v-model:value="settings.obsTitle"
|
||||
placeholder="默认为 点播"
|
||||
/>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</template>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-model:checked="settings.showRequireInfo" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showRequireInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示底部的需求信息
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showUserName" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showUserName"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示点播用户名
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showFanMadelInfo" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showFanMadelInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示点播用户粉丝牌
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 其他 </NDivider>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose"> 自动关闭点播失败时的提示消息 </NCheckbox>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose">
|
||||
自动关闭点播失败时的提示消息
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
</NSpin>
|
||||
</NTabPane>
|
||||
</NTabs>
|
||||
<template v-else>
|
||||
<NAlert title="未启用" type="error"> 请先启用弹幕点播功能 </NAlert>
|
||||
<NAlert
|
||||
title="未启用"
|
||||
type="error"
|
||||
>
|
||||
请先启用弹幕点播功能
|
||||
</NAlert>
|
||||
</template>
|
||||
</NCard>
|
||||
<NModal v-model:show="showOBSModal" title="OBS组件" preset="card" style="width: 800px">
|
||||
<NAlert title="这是什么? " type="info"> 将等待队列以及结果显示在OBS中 </NAlert>
|
||||
<NModal
|
||||
v-model:show="showOBSModal"
|
||||
title="OBS组件"
|
||||
preset="card"
|
||||
style="width: 800px"
|
||||
>
|
||||
<NAlert
|
||||
title="这是什么? "
|
||||
type="info"
|
||||
>
|
||||
将等待队列以及结果显示在OBS中
|
||||
</NAlert>
|
||||
<NDivider> 浏览 </NDivider>
|
||||
<div style="height: 500px; width: 280px; position: relative; margin: 0 auto">
|
||||
<LiveRequestOBS :id="accountInfo?.id" />
|
||||
</div>
|
||||
<br />
|
||||
<br>
|
||||
<NInput :value="`${CURRENT_HOST}obs/live-request?id=` + accountInfo?.id" />
|
||||
<NDivider />
|
||||
<NCollapse>
|
||||
|
||||
@@ -382,51 +382,120 @@ onUnmounted(() => {
|
||||
|
||||
<template>
|
||||
<NSpace>
|
||||
<NAlert type="info"> 搜索时会优先选择非VIP歌曲, 所以点到付费曲目时可能会是猴版或者各种奇怪的歌 </NAlert>
|
||||
<NAlert type="info">
|
||||
搜索时会优先选择非VIP歌曲, 所以点到付费曲目时可能会是猴版或者各种奇怪的歌
|
||||
</NAlert>
|
||||
</NSpace>
|
||||
<NDivider />
|
||||
<NSpace align="center">
|
||||
<NButton @click="listening ? stopListen() : startListen()" :type="listening ? 'error' : 'primary'"
|
||||
:style="{ animation: listening ? 'animated-border 2.5s infinite' : '' }" data-umami-event="Use Music Request"
|
||||
:data-umami-event-uid="accountInfo?.biliId" size="large">
|
||||
<NButton
|
||||
:type="listening ? 'error' : 'primary'"
|
||||
:style="{ animation: listening ? 'animated-border 2.5s infinite' : '' }"
|
||||
data-umami-event="Use Music Request"
|
||||
:data-umami-event-uid="accountInfo?.biliId"
|
||||
size="large"
|
||||
@click="listening ? stopListen() : startListen()"
|
||||
>
|
||||
{{ listening ? '停止监听' : '开始监听' }}
|
||||
</NButton>
|
||||
<NButton @click="showOBSModal = true" type="info" size="small"> OBS组件 </NButton>
|
||||
<NButton @click="showNeteaseModal = true" size="small"> 从网易云歌单导入空闲歌单 </NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
size="small"
|
||||
@click="showOBSModal = true"
|
||||
>
|
||||
OBS组件
|
||||
</NButton>
|
||||
<NButton
|
||||
size="small"
|
||||
@click="showNeteaseModal = true"
|
||||
>
|
||||
从网易云歌单导入空闲歌单
|
||||
</NButton>
|
||||
|
||||
<NButton @click="uploadConfig" type="primary" secondary :disabled="!accountInfo" size="small">
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
:disabled="!accountInfo"
|
||||
size="small"
|
||||
@click="uploadConfig"
|
||||
>
|
||||
保存配置到服务器
|
||||
</NButton>
|
||||
<NPopconfirm @positive-click="downloadConfig">
|
||||
<template #trigger>
|
||||
<NButton type="primary" secondary :disabled="!accountInfo" size="small"> 从服务器获取配置 </NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
:disabled="!accountInfo"
|
||||
size="small"
|
||||
>
|
||||
从服务器获取配置
|
||||
</NButton>
|
||||
</template>
|
||||
这将覆盖当前设置, 确定?
|
||||
</NPopconfirm>
|
||||
</NSpace>
|
||||
<NDivider />
|
||||
<NCollapse :default-expanded-names="['1']">
|
||||
<NCollapseItem title="队列" name="1">
|
||||
<NEmpty v-if="musicRquestStore.waitingMusics.length == 0"> 暂无 </NEmpty>
|
||||
<NList v-else size="small" bordered>
|
||||
<NListItem v-for="item in musicRquestStore.waitingMusics" :key="item.music.name">
|
||||
<NCollapseItem
|
||||
title="队列"
|
||||
name="1"
|
||||
>
|
||||
<NEmpty v-if="musicRquestStore.waitingMusics.length == 0">
|
||||
暂无
|
||||
</NEmpty>
|
||||
<NList
|
||||
v-else
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<NListItem
|
||||
v-for="item in musicRquestStore.waitingMusics"
|
||||
:key="item.music.name"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<NButton @click="musicRquestStore.playMusic(item.music)" type="primary" secondary size="small">
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
size="small"
|
||||
@click="musicRquestStore.playMusic(item.music)"
|
||||
>
|
||||
播放
|
||||
</NButton>
|
||||
<NButton @click="musicRquestStore.waitingMusics.splice(musicRquestStore.waitingMusics.indexOf(item), 1)"
|
||||
type="error" secondary size="small">
|
||||
<NButton
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
@click="musicRquestStore.waitingMusics.splice(musicRquestStore.waitingMusics.indexOf(item), 1)"
|
||||
>
|
||||
取消
|
||||
</NButton>
|
||||
<NButton @click="blockMusic(item.music)" type="warning" secondary size="small"> 拉黑 </NButton>
|
||||
<NButton
|
||||
type="warning"
|
||||
secondary
|
||||
size="small"
|
||||
@click="blockMusic(item.music)"
|
||||
>
|
||||
拉黑
|
||||
</NButton>
|
||||
<span>
|
||||
<NTag v-if="item.music.from == SongFrom.Netease" type="success" size="small"> 网易</NTag>
|
||||
<NTag v-else-if="item.music.from == SongFrom.Kugou" type="success" size="small"> 酷狗</NTag>
|
||||
<NTag
|
||||
v-if="item.music.from == SongFrom.Netease"
|
||||
type="success"
|
||||
size="small"
|
||||
> 网易</NTag>
|
||||
<NTag
|
||||
v-else-if="item.music.from == SongFrom.Kugou"
|
||||
type="success"
|
||||
size="small"
|
||||
> 酷狗</NTag>
|
||||
</span>
|
||||
<NText>
|
||||
{{ item.from.name }}
|
||||
</NText>
|
||||
<NText depth="3"> {{ item.music.name }} - {{ item.music.author?.join('/') }} </NText>
|
||||
<NText depth="3">
|
||||
{{ item.music.name }} - {{ item.music.author?.join('/') }}
|
||||
</NText>
|
||||
</NSpace>
|
||||
</NListItem>
|
||||
</NList>
|
||||
@@ -434,84 +503,157 @@ onUnmounted(() => {
|
||||
</NCollapse>
|
||||
<NDivider />
|
||||
<NTabs>
|
||||
<NTabPane name="settings" tab="设置">
|
||||
<NTabPane
|
||||
name="settings"
|
||||
tab="设置"
|
||||
>
|
||||
<NSpace vertical>
|
||||
<NSpace align="center">
|
||||
<NRadioGroup v-model:value="settings.platform">
|
||||
<NRadioButton value="netease"> 网易云 </NRadioButton>
|
||||
<NRadioButton value="kugou"> 酷狗 </NRadioButton>
|
||||
<NRadioButton value="netease">
|
||||
网易云
|
||||
</NRadioButton>
|
||||
<NRadioButton value="kugou">
|
||||
酷狗
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 点歌弹幕前缀 </NInputGroupLabel>
|
||||
<NInput v-model:value="settings.orderPrefix" />
|
||||
</NInputGroup>
|
||||
<NCheckbox :checked="settings.orderCooldown != undefined" @update:checked="(checked: boolean) => {
|
||||
settings.orderCooldown = checked ? 300 : undefined
|
||||
}
|
||||
">
|
||||
<NCheckbox
|
||||
:checked="settings.orderCooldown != undefined"
|
||||
@update:checked="(checked: boolean) => {
|
||||
settings.orderCooldown = checked ? 300 : undefined
|
||||
}
|
||||
"
|
||||
>
|
||||
是否启用点歌冷却
|
||||
</NCheckbox>
|
||||
<NInputGroup v-if="settings.orderCooldown" style="width: 200px">
|
||||
<NInputGroup
|
||||
v-if="settings.orderCooldown"
|
||||
style="width: 200px"
|
||||
>
|
||||
<NInputGroupLabel> 冷却时间 (秒) </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.orderCooldown" @update:value="(value) => {
|
||||
if (!value || value <= 0) settings.orderCooldown = undefined
|
||||
}
|
||||
" />
|
||||
<NInputNumber
|
||||
v-model:value="settings.orderCooldown"
|
||||
@update:value="(value) => {
|
||||
if (!value || value <= 0) settings.orderCooldown = undefined
|
||||
}
|
||||
"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NSpace>
|
||||
<NCheckbox v-model:checked="settings.playMusicWhenFree"> 空闲时播放空闲歌单 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.orderMusicFirst"> 优先播放点歌 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.playMusicWhenFree">
|
||||
空闲时播放空闲歌单
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.orderMusicFirst">
|
||||
优先播放点歌
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NSpace>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton @click="getOutputDevice" type="info"> 获取输出设备 </NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
@click="getOutputDevice"
|
||||
>
|
||||
获取输出设备
|
||||
</NButton>
|
||||
</template>
|
||||
获取和修改输出设备需要打开麦克风权限
|
||||
</NTooltip>
|
||||
<NSelect v-model:value="settings.deviceId" :options="deviceList"
|
||||
:fallback-option="() => ({ label: '未选择', value: '' })" style="min-width: 200px"
|
||||
@update:value="musicRquestStore.setSinkId" />
|
||||
<NSelect
|
||||
v-model:value="settings.deviceId"
|
||||
:options="deviceList"
|
||||
:fallback-option="() => ({ label: '未选择', value: '' })"
|
||||
style="min-width: 200px"
|
||||
@update:value="musicRquestStore.setSinkId"
|
||||
/>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
</NTabPane>
|
||||
<NTabPane name="list" tab="闲置歌单">
|
||||
<NTabPane
|
||||
name="list"
|
||||
tab="闲置歌单"
|
||||
>
|
||||
<NSpace>
|
||||
<NPopconfirm @positive-click="clearMusic">
|
||||
<template #trigger>
|
||||
<NButton type="error"> 清空 </NButton>
|
||||
<NButton type="error">
|
||||
清空
|
||||
</NButton>
|
||||
</template>
|
||||
确定清空吗?
|
||||
</NPopconfirm>
|
||||
<NButton @click="showNeteaseModal = true"> 从网易云歌单导入 </NButton>
|
||||
<NButton @click="showNeteaseModal = true">
|
||||
从网易云歌单导入
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NDivider style="margin: 15px 0 10px 0" />
|
||||
<NEmpty v-if="musicRquestStore.originMusics.length == 0"> 暂无 </NEmpty>
|
||||
<NVirtualList v-else :style="`max-height: 1000px`" :item-size="30" :items="originMusics" item-resizable>
|
||||
<NEmpty v-if="musicRquestStore.originMusics.length == 0">
|
||||
暂无
|
||||
</NEmpty>
|
||||
<NVirtualList
|
||||
v-else
|
||||
:style="`max-height: 1000px`"
|
||||
:item-size="30"
|
||||
:items="originMusics"
|
||||
item-resizable
|
||||
>
|
||||
<template #default="{ item }">
|
||||
<p :style="`min-height: ${30}px;width:97%;display:flex;align-items:center;`">
|
||||
<NSpace align="center" style="width: 100%">
|
||||
<NSpace
|
||||
align="center"
|
||||
style="width: 100%"
|
||||
>
|
||||
<NPopconfirm @positive-click="delMusic(item)">
|
||||
<template #trigger>
|
||||
<NButton type="error" secondary size="small"> 删除 </NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
</template>
|
||||
确定删除?
|
||||
</NPopconfirm>
|
||||
|
||||
<NButton type="info" secondary size="small" @click="musicRquestStore.playMusic(item)"> 播放 </NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
secondary
|
||||
size="small"
|
||||
@click="musicRquestStore.playMusic(item)"
|
||||
>
|
||||
播放
|
||||
</NButton>
|
||||
<NText> {{ item.name }} - {{ item.author?.join('/') }} </NText>
|
||||
</NSpace>
|
||||
</p>
|
||||
</template>
|
||||
</NVirtualList>
|
||||
</NTabPane>
|
||||
<NTabPane name="blacklist" tab="黑名单">
|
||||
<NTabPane
|
||||
name="blacklist"
|
||||
tab="黑名单"
|
||||
>
|
||||
<NList>
|
||||
<NListItem v-for="item in settings.blacklist" :key="item">
|
||||
<NSpace align="center" style="width: 100%">
|
||||
<NButton @click="settings.blacklist.splice(settings.blacklist.indexOf(item), 1)" type="error" secondary
|
||||
size="small">
|
||||
<NListItem
|
||||
v-for="item in settings.blacklist"
|
||||
:key="item"
|
||||
>
|
||||
<NSpace
|
||||
align="center"
|
||||
style="width: 100%"
|
||||
>
|
||||
<NButton
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
@click="settings.blacklist.splice(settings.blacklist.indexOf(item), 1)"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
<NText> {{ item }} </NText>
|
||||
@@ -521,34 +663,75 @@ onUnmounted(() => {
|
||||
</NTabPane>
|
||||
</NTabs>
|
||||
<NDivider style="height: 100px" />
|
||||
<NModal v-model:show="showNeteaseModal" preset="card" :title="`获取歌单`" style="max-width: 600px">
|
||||
<NInput clearable style="width: 100%" autosize :status="neteaseSongListId ? 'success' : 'error'"
|
||||
v-model:value="neteaseIdInput" placeholder="直接输入歌单Id或者网页链接">
|
||||
<NModal
|
||||
v-model:show="showNeteaseModal"
|
||||
preset="card"
|
||||
:title="`获取歌单`"
|
||||
style="max-width: 600px"
|
||||
>
|
||||
<NInput
|
||||
v-model:value="neteaseIdInput"
|
||||
clearable
|
||||
style="width: 100%"
|
||||
autosize
|
||||
:status="neteaseSongListId ? 'success' : 'error'"
|
||||
placeholder="直接输入歌单Id或者网页链接"
|
||||
>
|
||||
<template #suffix>
|
||||
<NTag v-if="neteaseSongListId" type="success" size="small"> 歌单Id: {{ neteaseSongListId }} </NTag>
|
||||
<NTag
|
||||
v-if="neteaseSongListId"
|
||||
type="success"
|
||||
size="small"
|
||||
>
|
||||
歌单Id: {{ neteaseSongListId }}
|
||||
</NTag>
|
||||
</template>
|
||||
</NInput>
|
||||
<NDivider style="margin: 10px" />
|
||||
<NButton type="primary" @click="getNeteaseSongList" :disabled="!neteaseSongListId" :loading="isLoading">
|
||||
<NButton
|
||||
type="primary"
|
||||
:disabled="!neteaseSongListId"
|
||||
:loading="isLoading"
|
||||
@click="getNeteaseSongList"
|
||||
>
|
||||
获取
|
||||
</NButton>
|
||||
<template v-if="neteaseSongsOptions.length > 0">
|
||||
<NDivider style="margin: 10px" />
|
||||
<NTransfer style="height: 500px" ref="transfer" v-model:value="selectedNeteaseSongs"
|
||||
:options="neteaseSongsOptions" source-filterable />
|
||||
<NTransfer
|
||||
ref="transfer"
|
||||
v-model:value="selectedNeteaseSongs"
|
||||
style="height: 500px"
|
||||
:options="neteaseSongsOptions"
|
||||
source-filterable
|
||||
/>
|
||||
<NDivider style="margin: 10px" />
|
||||
<NButton type="primary" @click="addNeteaseSongs" :loading="isLoading">
|
||||
<NButton
|
||||
type="primary"
|
||||
:loading="isLoading"
|
||||
@click="addNeteaseSongs"
|
||||
>
|
||||
添加到歌单 | {{ selectedNeteaseSongs.length }} 首
|
||||
</NButton>
|
||||
</template>
|
||||
</NModal>
|
||||
<NModal v-model:show="showOBSModal" title="OBS组件" preset="card" style="width: 800px">
|
||||
<NAlert title="这是什么? " type="info"> 将等待队列以及结果显示在OBS中 </NAlert>
|
||||
<NModal
|
||||
v-model:show="showOBSModal"
|
||||
title="OBS组件"
|
||||
preset="card"
|
||||
style="width: 800px"
|
||||
>
|
||||
<NAlert
|
||||
title="这是什么? "
|
||||
type="info"
|
||||
>
|
||||
将等待队列以及结果显示在OBS中
|
||||
</NAlert>
|
||||
<NDivider> 浏览 </NDivider>
|
||||
<div style="height: 500px; width: 280px; position: relative; margin: 0 auto">
|
||||
<MusicRequestOBS :id="accountInfo?.id" />
|
||||
</div>
|
||||
<br />
|
||||
<br>
|
||||
<NInput :value="`${CURRENT_HOST}obs/music-request?id=` + accountInfo?.id" />
|
||||
<NDivider />
|
||||
<NCollapse>
|
||||
|
||||
@@ -14,61 +14,135 @@ const accountInfo = useAccount()
|
||||
<template>
|
||||
<NDivider> 功能 </NDivider>
|
||||
<NSpace justify="center">
|
||||
<NCard hoverable embedded size="small" title="弹幕抽奖" style="width: 300px">
|
||||
<NCard
|
||||
hoverable
|
||||
embedded
|
||||
size="small"
|
||||
title="弹幕抽奖"
|
||||
style="width: 300px"
|
||||
>
|
||||
通过弹幕或者礼物收集用户, 并进行抽取, 允许设置多种条件
|
||||
<template #footer>
|
||||
<NButton @click="$router.push({ name: 'open-live-lottery', query: $route.query })" type="primary">
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="$router.push({ name: 'open-live-lottery', query: $route.query })"
|
||||
>
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
<NCard hoverable embedded size="small" title="弹幕点播" style="width: 300px">
|
||||
<NCard
|
||||
hoverable
|
||||
embedded
|
||||
size="small"
|
||||
title="弹幕点播"
|
||||
style="width: 300px"
|
||||
>
|
||||
通过弹幕或者SC进行点歌或者其他的点播(比如跳舞或者点播视频之类的), 注册后可以保存和导出
|
||||
<template #footer>
|
||||
<NButton @click="$router.push({ name: 'open-live-live-request', query: $route.query })" type="primary">
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="$router.push({ name: 'open-live-live-request', query: $route.query })"
|
||||
>
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
<NCard hoverable embedded size="small" title="弹幕排队" style="width: 300px">
|
||||
<NCard
|
||||
hoverable
|
||||
embedded
|
||||
size="small"
|
||||
title="弹幕排队"
|
||||
style="width: 300px"
|
||||
>
|
||||
通过发送弹幕或者礼物进行排队, 允许设置多种条件
|
||||
<template #footer>
|
||||
<NButton @click="$router.push({ name: 'open-live-queue', query: $route.query })" type="primary">
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="$router.push({ name: 'open-live-queue', query: $route.query })"
|
||||
>
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
|
||||
<NCard hoverable embedded size="small" title="读弹幕" style="width: 300px">
|
||||
<NCard
|
||||
hoverable
|
||||
embedded
|
||||
size="small"
|
||||
title="读弹幕"
|
||||
style="width: 300px"
|
||||
>
|
||||
通过浏览器自带的tts服务读弹幕 (此功能需要 Chrome, Edge 等现代浏览器!)
|
||||
<template #footer>
|
||||
<NButton @click="$router.push({ name: 'open-live-speech', query: $route.query })" type="primary">
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="$router.push({ name: 'open-live-speech', query: $route.query })"
|
||||
>
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
<br />
|
||||
<NAlert v-if="accountInfo?.eventFetcherState?.online != true" type="warning" title="可用性警告"
|
||||
style="max-width: 600px; margin: 0 auto">
|
||||
<br>
|
||||
<NAlert
|
||||
v-if="accountInfo?.eventFetcherState?.online != true"
|
||||
type="warning"
|
||||
title="可用性警告"
|
||||
style="max-width: 600px; margin: 0 auto"
|
||||
>
|
||||
当浏览器在后台运行时, 定时器和 Websocket 连接将受到严格限制, 这会导致弹幕接收功能无法正常工作 (详见
|
||||
<NButton text tag="a" href="https://developer.chrome.com/blog/background_tabs/" target="_blank" type="info">此文章
|
||||
<NButton
|
||||
text
|
||||
tag="a"
|
||||
href="https://developer.chrome.com/blog/background_tabs/"
|
||||
target="_blank"
|
||||
type="info"
|
||||
>
|
||||
此文章
|
||||
</NButton>), 虽然本站已经针对此问题做出了处理, 一般情况下即使掉线了也会重连, 不过还是有可能会遗漏事件
|
||||
<br />
|
||||
<br>
|
||||
为避免这种情况, 建议注册本站账后使用
|
||||
<NButton type="primary" text size="tiny" tag="a" href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs"
|
||||
target="_blank">
|
||||
VtsuruEventFetcher </NButton>, 否则请在使用功能时尽量保持网页在前台运行
|
||||
<NButton
|
||||
type="primary"
|
||||
text
|
||||
size="tiny"
|
||||
tag="a"
|
||||
href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs"
|
||||
target="_blank"
|
||||
>
|
||||
VtsuruEventFetcher
|
||||
</NButton>, 否则请在使用功能时尽量保持网页在前台运行
|
||||
</NAlert>
|
||||
<NDivider> 还有更多 </NDivider>
|
||||
<NSpace justify="center" align="center" vertical>
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
vertical
|
||||
>
|
||||
舰长积分、动态抽奖、视频征集、歌单、棉花糖、日程表...
|
||||
<p>
|
||||
详见
|
||||
<NButton text tag="a" href="/" target="_blank" type="primary"> VTsuru.live </NButton>
|
||||
<NButton
|
||||
text
|
||||
tag="a"
|
||||
href="/"
|
||||
target="_blank"
|
||||
type="primary"
|
||||
>
|
||||
VTsuru.live
|
||||
</NButton>
|
||||
|
||||
<NDivider vertical />
|
||||
<NButton text tag="a" href="/about" target="_blank" type="info"> 关于本站 </NButton>
|
||||
<NButton
|
||||
text
|
||||
tag="a"
|
||||
href="/about"
|
||||
target="_blank"
|
||||
type="info"
|
||||
>
|
||||
关于本站
|
||||
</NButton>
|
||||
</p>
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
@@ -342,52 +342,134 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NResult v-if="!code && !accountInfo" status="403" title="403" description="该页面只能从幻星平台访问或者注册用户使用" />
|
||||
<NResult
|
||||
v-if="!code && !accountInfo"
|
||||
status="403"
|
||||
title="403"
|
||||
description="该页面只能从幻星平台访问或者注册用户使用"
|
||||
/>
|
||||
<template v-else>
|
||||
<NCard>
|
||||
<template #header>
|
||||
直播抽奖
|
||||
<NDivider vertical />
|
||||
<NButton text type="primary" tag="a" href="https://vtsuru.live" target="_blank">
|
||||
<NButton
|
||||
text
|
||||
type="primary"
|
||||
tag="a"
|
||||
href="https://vtsuru.live"
|
||||
target="_blank"
|
||||
>
|
||||
前往 VTsuru.live 主站
|
||||
</NButton>
|
||||
</template>
|
||||
<NAlert v-if="!code && accountInfo && !accountInfo.isBiliVerified" type="error"> 请先绑定B站账号 </NAlert>
|
||||
<NAlert v-else-if="!code && accountInfo && accountInfo.biliAuthCodeStatus != 1" type="error">
|
||||
<NAlert
|
||||
v-if="!code && accountInfo && !accountInfo.isBiliVerified"
|
||||
type="error"
|
||||
>
|
||||
请先绑定B站账号
|
||||
</NAlert>
|
||||
<NAlert
|
||||
v-else-if="!code && accountInfo && accountInfo.biliAuthCodeStatus != 1"
|
||||
type="error"
|
||||
>
|
||||
身份码状态异常, 请重新绑定
|
||||
</NAlert>
|
||||
<NCard>
|
||||
<NSpace align="center">
|
||||
<NButton type="info" @click="showModal = true" size="small"> 抽奖历史</NButton>
|
||||
<NButton type="success" @click="showOBSModal = true" size="small"> OBS组件</NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
size="small"
|
||||
@click="showModal = true"
|
||||
>
|
||||
抽奖历史
|
||||
</NButton>
|
||||
<NButton
|
||||
type="success"
|
||||
size="small"
|
||||
@click="showOBSModal = true"
|
||||
>
|
||||
OBS组件
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NCard size="small" embedded title="抽奖选项">
|
||||
<NCard
|
||||
size="small"
|
||||
embedded
|
||||
title="抽奖选项"
|
||||
>
|
||||
<template #header-extra>
|
||||
<NButton size="small" secondary @click="lotteryOption = defaultOption" :disabled="isStartLottery">
|
||||
<NButton
|
||||
size="small"
|
||||
secondary
|
||||
:disabled="isStartLottery"
|
||||
@click="lotteryOption = defaultOption"
|
||||
>
|
||||
恢复默认
|
||||
</NButton>
|
||||
</template>
|
||||
<NSpace justify="center" align="center">
|
||||
<NTag :bordered="false"> 抽奖类型 </NTag>
|
||||
<NRadioGroup v-model:value="lotteryOption.type" :disabled="isLottering" size="small">
|
||||
<NRadioButton value="danmaku" :disabled="isStartLottery"> 弹幕 </NRadioButton>
|
||||
<NRadioButton value="gift" :disabled="isStartLottery"> 礼物 </NRadioButton>
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<NTag :bordered="false">
|
||||
抽奖类型
|
||||
</NTag>
|
||||
<NRadioGroup
|
||||
v-model:value="lotteryOption.type"
|
||||
:disabled="isLottering"
|
||||
size="small"
|
||||
>
|
||||
<NRadioButton
|
||||
value="danmaku"
|
||||
:disabled="isStartLottery"
|
||||
>
|
||||
弹幕
|
||||
</NRadioButton>
|
||||
<NRadioButton
|
||||
value="gift"
|
||||
:disabled="isStartLottery"
|
||||
>
|
||||
礼物
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NSpace>
|
||||
<NDivider style="margin: 10px 0 10px 0"></NDivider>
|
||||
<NDivider style="margin: 10px 0 10px 0" />
|
||||
<NSpace align="center">
|
||||
<NInputGroup style="max-width: 200px">
|
||||
<NInputGroupLabel> 抽选人数 </NInputGroupLabel>
|
||||
<NInputNumber :disabled="isStartLottery" v-model:value="lotteryOption.resultCount" placeholder="" min="1" />
|
||||
<NInputNumber
|
||||
v-model:value="lotteryOption.resultCount"
|
||||
:disabled="isStartLottery"
|
||||
placeholder=""
|
||||
min="1"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NCheckbox :disabled="isStartLottery" v-model:checked="lotteryOption.needGuard"> 需要上舰 </NCheckbox>
|
||||
<NCheckbox :disabled="isStartLottery" v-model:checked="lotteryOption.needFanMedal"> 需要粉丝牌 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="lotteryOption.needGuard"
|
||||
:disabled="isStartLottery"
|
||||
>
|
||||
需要上舰
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="lotteryOption.needFanMedal"
|
||||
:disabled="isStartLottery"
|
||||
>
|
||||
需要粉丝牌
|
||||
</NCheckbox>
|
||||
<NCollapseTransition>
|
||||
<NInputGroup v-if="lotteryOption.needFanMedal" style="max-width: 200px">
|
||||
<NInputGroup
|
||||
v-if="lotteryOption.needFanMedal"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
<NInputGroupLabel> 最低粉丝牌等级 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="lotteryOption.fanCardLevel" min="1" max="50" :default-value="1"
|
||||
:disabled="isLottering || isStartLottery" />
|
||||
<NInputNumber
|
||||
v-model:value="lotteryOption.fanCardLevel"
|
||||
min="1"
|
||||
max="50"
|
||||
:default-value="1"
|
||||
:disabled="isLottering || isStartLottery"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</NCollapseTransition>
|
||||
<template v-if="lotteryOption.type == 'danmaku'">
|
||||
@@ -395,35 +477,74 @@ onUnmounted(() => {
|
||||
<template #trigger>
|
||||
<NInputGroup style="max-width: 250px">
|
||||
<NInputGroupLabel> 弹幕内容 </NInputGroupLabel>
|
||||
<NInput :disabled="isStartLottery" v-model:value="lotteryOption.danmakuKeyword"
|
||||
placeholder="留空则任何弹幕都可以" />
|
||||
<NInput
|
||||
v-model:value="lotteryOption.danmakuKeyword"
|
||||
:disabled="isStartLottery"
|
||||
placeholder="留空则任何弹幕都可以"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</template>
|
||||
符合规则的弹幕才会被添加到抽奖队列中
|
||||
</NTooltip>
|
||||
<NRadioGroup v-model:value="lotteryOption.danmakuFilterType" name="判定类型" :disabled="isLottering"
|
||||
size="small">
|
||||
<NRadioButton :disabled="isStartLottery" value="all"> 完全一致 </NRadioButton>
|
||||
<NRadioButton :disabled="isStartLottery" value="contains"> 包含 </NRadioButton>
|
||||
<NRadioButton :disabled="isStartLottery" value="regex"> 正则 </NRadioButton>
|
||||
<NRadioGroup
|
||||
v-model:value="lotteryOption.danmakuFilterType"
|
||||
name="判定类型"
|
||||
:disabled="isLottering"
|
||||
size="small"
|
||||
>
|
||||
<NRadioButton
|
||||
:disabled="isStartLottery"
|
||||
value="all"
|
||||
>
|
||||
完全一致
|
||||
</NRadioButton>
|
||||
<NRadioButton
|
||||
:disabled="isStartLottery"
|
||||
value="contains"
|
||||
>
|
||||
包含
|
||||
</NRadioButton>
|
||||
<NRadioButton
|
||||
:disabled="isStartLottery"
|
||||
value="regex"
|
||||
>
|
||||
正则
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</template>
|
||||
<template v-else-if="lotteryOption.type == 'gift'">
|
||||
<NInputGroup style="max-width: 250px">
|
||||
<NInputGroupLabel> 最低价格 </NInputGroupLabel>
|
||||
<NInputNumber :disabled="isStartLottery" v-model:value="lotteryOption.giftMinPrice"
|
||||
placeholder="留空则不限制" />
|
||||
<NInputNumber
|
||||
v-model:value="lotteryOption.giftMinPrice"
|
||||
:disabled="isStartLottery"
|
||||
placeholder="留空则不限制"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="max-width: 200px">
|
||||
<NInputGroupLabel> 礼物名称 </NInputGroupLabel>
|
||||
<NInput :disabled="isStartLottery" v-model:value="lotteryOption.giftName" placeholder="留空则不限制" />
|
||||
<NInput
|
||||
v-model:value="lotteryOption.giftName"
|
||||
:disabled="isStartLottery"
|
||||
placeholder="留空则不限制"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</template>
|
||||
</NSpace>
|
||||
<NDivider style="margin: 10px 0 10px 0"></NDivider>
|
||||
<NSpace justify="center" align="center">
|
||||
<NTag :bordered="false"> 抽取方式 </NTag>
|
||||
<NRadioGroup v-model:value="lotteryOption.lotteryType" name="抽取类型" size="small" :disabled="isLottering">
|
||||
<NDivider style="margin: 10px 0 10px 0" />
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<NTag :bordered="false">
|
||||
抽取方式
|
||||
</NTag>
|
||||
<NRadioGroup
|
||||
v-model:value="lotteryOption.lotteryType"
|
||||
name="抽取类型"
|
||||
size="small"
|
||||
:disabled="isLottering"
|
||||
>
|
||||
<NRadioButton value="single">
|
||||
单个
|
||||
<NTooltip>
|
||||
@@ -445,39 +566,107 @@ onUnmounted(() => {
|
||||
</NRadioGroup>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NCard v-if="originUsers" size="small">
|
||||
<NSpace justify="center" align="center">
|
||||
<NButton type="primary" @click="continueLottery" :loading="isStartLottery"
|
||||
:disabled="isStartLottery || isLotteried || !client">
|
||||
<NCard
|
||||
v-if="originUsers"
|
||||
size="small"
|
||||
>
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<NButton
|
||||
type="primary"
|
||||
:loading="isStartLottery"
|
||||
:disabled="isStartLottery || isLotteried || !client"
|
||||
@click="continueLottery"
|
||||
>
|
||||
开始
|
||||
</NButton>
|
||||
<NButton type="warning" :disabled="!isStartLottery" @click="pause"> 停止 </NButton>
|
||||
<NButton type="error" :disabled="isLottering || originUsers.length == 0" @click="clear"> 清空 </NButton>
|
||||
<NButton
|
||||
type="warning"
|
||||
:disabled="!isStartLottery"
|
||||
@click="pause"
|
||||
>
|
||||
停止
|
||||
</NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
:disabled="isLottering || originUsers.length == 0"
|
||||
@click="clear"
|
||||
>
|
||||
清空
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NDivider style="margin: 20px 0 20px 0">
|
||||
<template v-if="isStartLottery"> 进行抽取前需要先停止 </template>
|
||||
<template v-if="isStartLottery">
|
||||
进行抽取前需要先停止
|
||||
</template>
|
||||
</NDivider>
|
||||
<NSpace justify="center">
|
||||
<NButton type="primary" secondary @click="startLottery" :loading="isLottering"
|
||||
:disabled="isStartLottery || isLotteried" data-umami-event="Open-Live Use Lottery"
|
||||
:data-umami-event-uid="client?.authInfo?.anchor_info?.uid">
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
:loading="isLottering"
|
||||
:disabled="isStartLottery || isLotteried"
|
||||
data-umami-event="Open-Live Use Lottery"
|
||||
:data-umami-event-uid="client?.authInfo?.anchor_info?.uid"
|
||||
@click="startLottery"
|
||||
>
|
||||
进行抽取
|
||||
</NButton>
|
||||
<NButton type="info" secondary :disabled="isStartLottery || isLottering || !isLotteried" @click="reset">
|
||||
<NButton
|
||||
type="info"
|
||||
secondary
|
||||
:disabled="isStartLottery || isLottering || !isLotteried"
|
||||
@click="reset"
|
||||
>
|
||||
重置
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NDivider style="margin: 10px 0 10px 0"> 共 {{ currentUsers?.length }} 人</NDivider>
|
||||
<NGrid v-if="currentUsers.length > 0" cols="1 500:2 800:3 1000:4" :x-gap="12" :y-gap="8">
|
||||
<NGridItem v-for="item in currentUsers" v-bind:key="item.openId">
|
||||
<NCard size="small" :title="item.name" style="height: 155px" embedded>
|
||||
<NDivider style="margin: 10px 0 10px 0">
|
||||
共 {{ currentUsers?.length }} 人
|
||||
</NDivider>
|
||||
<NGrid
|
||||
v-if="currentUsers.length > 0"
|
||||
cols="1 500:2 800:3 1000:4"
|
||||
:x-gap="12"
|
||||
:y-gap="8"
|
||||
>
|
||||
<NGridItem
|
||||
v-for="item in currentUsers"
|
||||
:key="item.openId"
|
||||
>
|
||||
<NCard
|
||||
size="small"
|
||||
:title="item.name"
|
||||
style="height: 155px"
|
||||
embedded
|
||||
>
|
||||
<template #header>
|
||||
<NSpace align="center" vertical :size="5">
|
||||
<NAvatar round lazy borderd :size="64" :src="item.avatar + '@64w_64h'"
|
||||
:img-props="{ referrerpolicy: 'no-referrer' }" style="box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2)" />
|
||||
<NSpace
|
||||
align="center"
|
||||
vertical
|
||||
:size="5"
|
||||
>
|
||||
<NAvatar
|
||||
round
|
||||
lazy
|
||||
borderd
|
||||
:size="64"
|
||||
:src="item.avatar + '@64w_64h'"
|
||||
:img-props="{ referrerpolicy: 'no-referrer' }"
|
||||
style="box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2)"
|
||||
/>
|
||||
<NSpace v-if="item.fans_medal_wearing_status">
|
||||
<NTag size="tiny" round>
|
||||
<NTag size="tiny" round :bordered="false">
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
>
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
:bordered="false"
|
||||
>
|
||||
{{ item.fans_medal_level }}
|
||||
</NTag>
|
||||
<span style="color: #577fb8">
|
||||
@@ -485,12 +674,23 @@ onUnmounted(() => {
|
||||
</span>
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<NTag v-else size="tiny" round :bordered="false"> 无粉丝牌 </NTag>
|
||||
<NTag
|
||||
v-else
|
||||
size="tiny"
|
||||
round
|
||||
:bordered="false"
|
||||
>
|
||||
无粉丝牌
|
||||
</NTag>
|
||||
{{ item.name }}
|
||||
</NSpace>
|
||||
|
||||
<NButton style="position: absolute; right: 5px; top: 5px; color: #753e3e" @click="removeUser(item)"
|
||||
size="small" circle>
|
||||
<NButton
|
||||
style="position: absolute; right: 5px; top: 5px; color: #753e3e"
|
||||
size="small"
|
||||
circle
|
||||
@click="removeUser(item)"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Delete24Filled" />
|
||||
</template>
|
||||
@@ -499,29 +699,62 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
</NGridItem>
|
||||
</NGrid>
|
||||
<NEmpty v-else description="暂无用户" />
|
||||
<NEmpty
|
||||
v-else
|
||||
description="暂无用户"
|
||||
/>
|
||||
</NCard>
|
||||
</NCard>
|
||||
</template>
|
||||
<NModal v-model:show="showModal" preset="card" title="抽奖结果" style="max-width: 90%; width: 800px" closable>
|
||||
<NModal
|
||||
v-model:show="showModal"
|
||||
preset="card"
|
||||
title="抽奖结果"
|
||||
style="max-width: 90%; width: 800px"
|
||||
closable
|
||||
>
|
||||
<template #header-extra>
|
||||
<NButton type="error" size="small" @click="lotteryHistory = []"> 清空 </NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
size="small"
|
||||
@click="lotteryHistory = []"
|
||||
>
|
||||
清空
|
||||
</NButton>
|
||||
</template>
|
||||
<NScrollbar v-if="lotteryHistory.length > 0" style="max-height: 80vh">
|
||||
<NScrollbar
|
||||
v-if="lotteryHistory.length > 0"
|
||||
style="max-height: 80vh"
|
||||
>
|
||||
<NList>
|
||||
<NListItem v-for="item in lotteryHistory" :key="item.time">
|
||||
<NListItem
|
||||
v-for="item in lotteryHistory"
|
||||
:key="item.time"
|
||||
>
|
||||
<NCard size="small">
|
||||
<template #header>
|
||||
<NTime :time="item.time" />
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NButton type="error" size="small" @click="lotteryHistory.splice(lotteryHistory.indexOf(item), 1)">
|
||||
<NButton
|
||||
type="error"
|
||||
size="small"
|
||||
@click="lotteryHistory.splice(lotteryHistory.indexOf(item), 1)"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
</template>
|
||||
<NSpace vertical>
|
||||
<NSpace v-for="user in item.users" :key="user.openId">
|
||||
<NAvatar round lazy :src="user.avatar + '@64w_64h'" :img-props="{ referrerpolicy: 'no-referrer' }" />
|
||||
<NSpace
|
||||
v-for="user in item.users"
|
||||
:key="user.openId"
|
||||
>
|
||||
<NAvatar
|
||||
round
|
||||
lazy
|
||||
:src="user.avatar + '@64w_64h'"
|
||||
:img-props="{ referrerpolicy: 'no-referrer' }"
|
||||
/>
|
||||
{{ user.name }}
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
@@ -529,16 +762,30 @@ onUnmounted(() => {
|
||||
</NListItem>
|
||||
</NList>
|
||||
</NScrollbar>
|
||||
<NEmpty v-else description="暂无记录" />
|
||||
<NEmpty
|
||||
v-else
|
||||
description="暂无记录"
|
||||
/>
|
||||
</NModal>
|
||||
<NModal v-model:show="showOBSModal" preset="card" title="OBS 组件"
|
||||
style="max-width: 90%; width: 800px; max-height: 90vh" closable content-style="overflow: auto">
|
||||
<NAlert title="这是什么? " type="info"> 将等待队列以及结果显示在OBS中 </NAlert>
|
||||
<NModal
|
||||
v-model:show="showOBSModal"
|
||||
preset="card"
|
||||
title="OBS 组件"
|
||||
style="max-width: 90%; width: 800px; max-height: 90vh"
|
||||
closable
|
||||
content-style="overflow: auto"
|
||||
>
|
||||
<NAlert
|
||||
title="这是什么? "
|
||||
type="info"
|
||||
>
|
||||
将等待队列以及结果显示在OBS中
|
||||
</NAlert>
|
||||
<NDivider> 浏览 </NDivider>
|
||||
<div style="height: 400px; width: 250px; position: relative; margin: 0 auto">
|
||||
<LiveLotteryOBS :code="code" />
|
||||
</div>
|
||||
<br />
|
||||
<br>
|
||||
<NInput :value="`${CURRENT_HOST}obs/live-lottery?code=` + code" />
|
||||
<NDivider />
|
||||
<NCollapse>
|
||||
|
||||
@@ -762,91 +762,181 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NAlert :type="accountInfo.settings.enableFunctions.includes(FunctionTypes.Queue) ? 'success' : 'warning'"
|
||||
v-if="accountInfo.id">
|
||||
<NAlert
|
||||
v-if="accountInfo.id"
|
||||
:type="accountInfo.settings.enableFunctions.includes(FunctionTypes.Queue) ? 'success' : 'warning'"
|
||||
>
|
||||
启用弹幕队列功能
|
||||
<NSwitch :value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.Queue)"
|
||||
@update:value="onUpdateFunctionEnable" />
|
||||
<NSwitch
|
||||
:value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.Queue)"
|
||||
@update:value="onUpdateFunctionEnable"
|
||||
/>
|
||||
|
||||
<br />
|
||||
<br>
|
||||
<NText depth="3">
|
||||
如果没有部署
|
||||
<NButton text type="primary" tag="a" href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs" target="_blank">
|
||||
<NButton
|
||||
text
|
||||
type="primary"
|
||||
tag="a"
|
||||
href="https://www.wolai.com/fje5wLtcrDoZcb9rk2zrFs"
|
||||
target="_blank"
|
||||
>
|
||||
VtsuruEventFetcher
|
||||
</NButton>
|
||||
则其需要保持此页面开启才能使用, 也不要同时开多个页面, 会导致重复 !(部署了则不影响)
|
||||
</NText>
|
||||
</NAlert>
|
||||
<NAlert type="warning" v-else title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑">
|
||||
<NButton tag="a" href="/manage" target="_blank" type="primary"> 前往登录或注册 </NButton>
|
||||
<NAlert
|
||||
v-else
|
||||
type="warning"
|
||||
title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑"
|
||||
>
|
||||
<NButton
|
||||
tag="a"
|
||||
href="/manage"
|
||||
target="_blank"
|
||||
type="primary"
|
||||
>
|
||||
前往登录或注册
|
||||
</NButton>
|
||||
</NAlert>
|
||||
<br />
|
||||
<br>
|
||||
<NCard size="small">
|
||||
<NSpace align="center">
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton @click="showOBSModal = true" type="primary" :disabled="!accountInfo"> OBS 组件 </NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
:disabled="!accountInfo"
|
||||
@click="showOBSModal = true"
|
||||
>
|
||||
OBS 组件
|
||||
</NButton>
|
||||
</template>
|
||||
{{ configCanEdit ? '' : '登陆后才可以使用此功能' }}
|
||||
</NTooltip>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<br />
|
||||
<br>
|
||||
<NCard>
|
||||
<NTabs v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.Queue)" animated
|
||||
display-directive="show:lazy">
|
||||
<NTabPane name="list" tab="列表">
|
||||
<NTabs
|
||||
v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.Queue)"
|
||||
animated
|
||||
display-directive="show:lazy"
|
||||
>
|
||||
<NTabPane
|
||||
name="list"
|
||||
tab="列表"
|
||||
>
|
||||
<NCard size="small">
|
||||
<NSpace align="center">
|
||||
<NTag type="success" :bordered="false">
|
||||
<NTag
|
||||
type="success"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="PeopleQueue24Filled" />
|
||||
</template>
|
||||
队列 | {{queue.filter((s) => s.status == QueueStatus.Waiting).length}}
|
||||
队列 | {{ queue.filter((s) => s.status == QueueStatus.Waiting).length }}
|
||||
</NTag>
|
||||
<NTag type="success" :bordered="false">
|
||||
<NTag
|
||||
type="success"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Checkmark12Regular" />
|
||||
</template>
|
||||
今日已处理 |
|
||||
{{queue.filter((s) => s.status == QueueStatus.Finish && isSameDay(s.finishAt ?? 0, Date.now())).length}}
|
||||
{{ queue.filter((s) => s.status == QueueStatus.Finish && isSameDay(s.finishAt ?? 0, Date.now())).length }}
|
||||
位
|
||||
</NTag>
|
||||
<NInputGroup>
|
||||
<NInput placeholder="手动添加" v-model:value="newQueueName" />
|
||||
<NButton type="primary" @click="addManual"> 添加 </NButton>
|
||||
<NInput
|
||||
v-model:value="newQueueName"
|
||||
placeholder="手动添加"
|
||||
/>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="addManual"
|
||||
>
|
||||
添加
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NPopconfirm @positive-click="deactiveAllSongs">
|
||||
<template #trigger>
|
||||
<NButton type="error"> 全部取消 </NButton>
|
||||
<NButton type="error">
|
||||
全部取消
|
||||
</NButton>
|
||||
</template>
|
||||
确定全部取消吗?
|
||||
</NPopconfirm>
|
||||
<NRadioGroup v-model:value="settings.sortType" :disabled="!configCanEdit" @update:value="updateSettings"
|
||||
type="button">
|
||||
<NRadioButton :value="QueueSortType.TimeFirst"> 加入时间优先 </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.PaymentFist"> 付费价格优先 </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.GuardFirst"> 舰长优先 (按等级) </NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.FansMedalFirst"> 粉丝牌等级优先 </NRadioButton>
|
||||
<NRadioGroup
|
||||
v-model:value="settings.sortType"
|
||||
:disabled="!configCanEdit"
|
||||
type="button"
|
||||
@update:value="updateSettings"
|
||||
>
|
||||
<NRadioButton :value="QueueSortType.TimeFirst">
|
||||
加入时间优先
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.PaymentFist">
|
||||
付费价格优先
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.GuardFirst">
|
||||
舰长优先 (按等级)
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="QueueSortType.FansMedalFirst">
|
||||
粉丝牌等级优先
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-if="configCanEdit"
|
||||
v-model:checked="settings.isReverse"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
倒序
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-else
|
||||
v-model:checked="isReverse"
|
||||
>
|
||||
倒序
|
||||
</NCheckbox>
|
||||
<NCheckbox v-else v-model:checked="isReverse"> 倒序 </NCheckbox>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NDivider> 共 {{ queue.length }} 人 </NDivider>
|
||||
<NList v-if="queue.length > 0" :show-divider="false" hoverable>
|
||||
<NListItem v-for="(queueData, index) in queue" :key="queueData.id" style="padding: 5px">
|
||||
<NCard embedded size="small" content-style="padding: 5px;"
|
||||
:style="`${queueData.status == QueueStatus.Progressing ? 'animation: animated-border 2.5s infinite;' : ''};height: 100%;`">
|
||||
<NSpace justify="space-between" align="center" style="height: 100%; margin: 0 5px 0 5px">
|
||||
<NList
|
||||
v-if="queue.length > 0"
|
||||
:show-divider="false"
|
||||
hoverable
|
||||
>
|
||||
<NListItem
|
||||
v-for="(queueData, index) in queue"
|
||||
:key="queueData.id"
|
||||
style="padding: 5px"
|
||||
>
|
||||
<NCard
|
||||
embedded
|
||||
size="small"
|
||||
content-style="padding: 5px;"
|
||||
:style="`${queueData.status == QueueStatus.Progressing ? 'animation: animated-border 2.5s infinite;' : ''};height: 100%;`"
|
||||
>
|
||||
<NSpace
|
||||
justify="space-between"
|
||||
align="center"
|
||||
style="height: 100%; margin: 0 5px 0 5px"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<div
|
||||
:style="`border-radius: 4px; background-color: ${queueData.status == QueueStatus.Progressing ? '#75c37f' : '#577fb8'}; width: 20px; height: 20px;text-align: center;color: white;`">
|
||||
:style="`border-radius: 4px; background-color: ${queueData.status == QueueStatus.Progressing ? '#75c37f' : '#577fb8'}; width: 20px; height: 20px;text-align: center;color: white;`"
|
||||
>
|
||||
{{ index + 1 }}
|
||||
</div>
|
||||
<NText strong style="font-size: 18px">
|
||||
<NText
|
||||
strong
|
||||
style="font-size: 18px"
|
||||
>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
{{ queueData.user?.name }}
|
||||
@@ -855,14 +945,28 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
</NText>
|
||||
<template v-if="queueData.from == QueueFrom.Manual">
|
||||
<NTag size="small" :bordered="false"> 手动添加 </NTag>
|
||||
<NTag
|
||||
size="small"
|
||||
:bordered="false"
|
||||
>
|
||||
手动添加
|
||||
</NTag>
|
||||
</template>
|
||||
<NSpace v-if="
|
||||
(queueData.from == QueueFrom.Danmaku || queueData.from == QueueFrom.Gift) &&
|
||||
queueData.user?.fans_medal_wearing_status
|
||||
">
|
||||
<NTag size="tiny" round>
|
||||
<NTag size="tiny" round :bordered="false">
|
||||
<NSpace
|
||||
v-if="
|
||||
(queueData.from == QueueFrom.Danmaku || queueData.from == QueueFrom.Gift) &&
|
||||
queueData.user?.fans_medal_wearing_status
|
||||
"
|
||||
>
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
>
|
||||
<NTag
|
||||
size="tiny"
|
||||
round
|
||||
:bordered="false"
|
||||
>
|
||||
<NText depth="3">
|
||||
{{ queueData.user?.fans_medal_level }}
|
||||
</NText>
|
||||
@@ -872,29 +976,51 @@ onUnmounted(() => {
|
||||
</span>
|
||||
</NTag>
|
||||
</NSpace>
|
||||
<NTag v-if="(queueData.user?.guard_level ?? 0) > 0" size="small" :bordered="false"
|
||||
:color="{ textColor: 'white', color: GetGuardColor(queueData.user?.guard_level) }">
|
||||
<NTag
|
||||
v-if="(queueData.user?.guard_level ?? 0) > 0"
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:color="{ textColor: 'white', color: GetGuardColor(queueData.user?.guard_level) }"
|
||||
>
|
||||
{{ queueData.user?.guard_level == 1 ? '总督' : queueData.user?.guard_level == 2 ? '提督' : '舰长' }}
|
||||
</NTag>
|
||||
<NTag v-if="(queueData.giftPrice ?? 0) > 0" size="small" :bordered="false" type="error">
|
||||
<NTag
|
||||
v-if="(queueData.giftPrice ?? 0) > 0"
|
||||
size="small"
|
||||
:bordered="false"
|
||||
type="error"
|
||||
>
|
||||
付费 | {{ queueData.giftPrice }}
|
||||
</NTag>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText style="font-size: small">
|
||||
<NTime :time="queueData.createAt" type="relative" :key="updateKey" />
|
||||
<NTime
|
||||
:key="updateKey"
|
||||
:time="queueData.createAt"
|
||||
type="relative"
|
||||
/>
|
||||
</NText>
|
||||
</template>
|
||||
<NTime :time="queueData.createAt" />
|
||||
</NTooltip>
|
||||
|
||||
<NTooltip v-if="queueData.content" content-style="margin: 0">
|
||||
<NTooltip
|
||||
v-if="queueData.content"
|
||||
content-style="margin: 0"
|
||||
>
|
||||
<template #trigger>
|
||||
<NText strong style="font-size: 18px">
|
||||
<NText
|
||||
strong
|
||||
style="font-size: 18px"
|
||||
>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</NText>
|
||||
</template>
|
||||
<NCard size="small" :bordered="false">
|
||||
<NCard
|
||||
size="small"
|
||||
:bordered="false"
|
||||
>
|
||||
<template #header>
|
||||
<span style="font-size: small; color: gray;">
|
||||
{{ '来自' + (queueData?.from == QueueFrom.Gift ? '礼物' : '弹幕') + ': ' }}
|
||||
@@ -904,18 +1030,28 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
</NTooltip>
|
||||
</NSpace>
|
||||
<NSpace justify="end" align="center">
|
||||
<NSpace
|
||||
justify="end"
|
||||
align="center"
|
||||
>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="primary" style="height: 30px; width: 30px" :disabled="queue.findIndex((s) => s.id != queueData.id && s.status == QueueStatus.Progressing) > -1
|
||||
" @click="
|
||||
<NButton
|
||||
circle
|
||||
type="primary"
|
||||
style="height: 30px; width: 30px"
|
||||
:disabled="queue.findIndex((s) => s.id != queueData.id && s.status == QueueStatus.Progressing) > -1
|
||||
"
|
||||
:style="`animation: ${queueData.status == QueueStatus.Waiting ? '' : 'loading 5s linear infinite'}`"
|
||||
:secondary="queueData.status == QueueStatus.Progressing"
|
||||
:loading="isLoading"
|
||||
@click="
|
||||
updateStatus(
|
||||
queueData,
|
||||
queueData.status == QueueStatus.Progressing ? QueueStatus.Waiting : QueueStatus.Progressing,
|
||||
)
|
||||
"
|
||||
:style="`animation: ${queueData.status == QueueStatus.Waiting ? '' : 'loading 5s linear infinite'}`"
|
||||
:secondary="queueData.status == QueueStatus.Progressing" :loading="isLoading">
|
||||
"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="ClipboardTextLtr24Filled" />
|
||||
</template>
|
||||
@@ -931,8 +1067,13 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="success" style="height: 30px; width: 30px" :loading="isLoading"
|
||||
@click="updateStatus(queueData, QueueStatus.Finish)">
|
||||
<NButton
|
||||
circle
|
||||
type="success"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
@click="updateStatus(queueData, QueueStatus.Finish)"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Checkmark12Regular" />
|
||||
</template>
|
||||
@@ -944,7 +1085,12 @@ onUnmounted(() => {
|
||||
<template #trigger>
|
||||
<NPopconfirm @positive-click="blockUser(queueData)">
|
||||
<template #trigger>
|
||||
<NButton circle type="warning" style="height: 30px; width: 30px" :loading="isLoading">
|
||||
<NButton
|
||||
circle
|
||||
type="warning"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="PresenceBlocked16Regular" />
|
||||
</template>
|
||||
@@ -957,8 +1103,13 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NButton circle type="error" style="height: 30px; width: 30px" :loading="isLoading"
|
||||
@click="updateStatus(queueData, QueueStatus.Cancel)">
|
||||
<NButton
|
||||
circle
|
||||
type="error"
|
||||
style="height: 30px; width: 30px"
|
||||
:loading="isLoading"
|
||||
@click="updateStatus(queueData, QueueStatus.Cancel)"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Dismiss16Filled" />
|
||||
</template>
|
||||
@@ -971,31 +1122,51 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
</NListItem>
|
||||
</NList>
|
||||
<NEmpty v-else description="暂无用户" />
|
||||
<NEmpty
|
||||
v-else
|
||||
description="暂无用户"
|
||||
/>
|
||||
</NTabPane>
|
||||
<NTabPane name="history" tab="历史">
|
||||
<NTabPane
|
||||
name="history"
|
||||
tab="历史"
|
||||
>
|
||||
<NCard size="small">
|
||||
<NSpace>
|
||||
<NInputGroup style="width: 300px">
|
||||
<NInputGroupLabel> 筛选用户 </NInputGroupLabel>
|
||||
<NInput v-model:value="filterName" clearable>
|
||||
<NInput
|
||||
v-model:value="filterName"
|
||||
clearable
|
||||
>
|
||||
<template #suffix>
|
||||
<NCheckbox v-model:checked="filterNameContains"> 包含 </NCheckbox>
|
||||
<NCheckbox v-model:checked="filterNameContains">
|
||||
包含
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NInput>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NDataTable size="small" ref="table" :columns="columns" :data="originQueue" :pagination="{
|
||||
itemCount: originQueue.length,
|
||||
pageSizes: [20, 50, 100],
|
||||
showSizePicker: true,
|
||||
prefix({ itemCount }) {
|
||||
return `共 ${itemCount} 条记录`
|
||||
},
|
||||
}" />
|
||||
<NDataTable
|
||||
ref="table"
|
||||
size="small"
|
||||
:columns="columns"
|
||||
:data="originQueue"
|
||||
:pagination="{
|
||||
itemCount: originQueue.length,
|
||||
pageSizes: [20, 50, 100],
|
||||
showSizePicker: true,
|
||||
prefix({ itemCount }) {
|
||||
return `共 ${itemCount} 条记录`
|
||||
},
|
||||
}"
|
||||
/>
|
||||
</NTabPane>
|
||||
<NTabPane name="setting" tab="设置">
|
||||
<NTabPane
|
||||
name="setting"
|
||||
tab="设置"
|
||||
>
|
||||
<NSpin :show="isLoading">
|
||||
<NDivider> 规则 </NDivider>
|
||||
<NSpace vertical>
|
||||
@@ -1004,77 +1175,164 @@ onUnmounted(() => {
|
||||
<NInputGroupLabel> 加入队列关键词 </NInputGroupLabel>
|
||||
<template v-if="configCanEdit">
|
||||
<NInput v-model:value="settings.keyword" />
|
||||
<NButton @click="updateSettings" type="primary">确定</NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</template>
|
||||
<NInput v-else v-model:value="defaultKeyword" />
|
||||
<NInput
|
||||
v-else
|
||||
v-model:value="defaultKeyword"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NRadioGroup v-model:value="settings.matchType" :disabled="!configCanEdit" @update:value="updateSettings"
|
||||
type="button">
|
||||
<NRadioButton :value="KeywordMatchType.Full"> 完全一致 </NRadioButton>
|
||||
<NRadioButton :value="KeywordMatchType.Contains"> 包含 </NRadioButton>
|
||||
<NRadioButton :value="KeywordMatchType.Regex"> 正则 </NRadioButton>
|
||||
<NRadioGroup
|
||||
v-model:value="settings.matchType"
|
||||
:disabled="!configCanEdit"
|
||||
type="button"
|
||||
@update:value="updateSettings"
|
||||
>
|
||||
<NRadioButton :value="KeywordMatchType.Full">
|
||||
完全一致
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="KeywordMatchType.Contains">
|
||||
包含
|
||||
</NRadioButton>
|
||||
<NRadioButton :value="KeywordMatchType.Regex">
|
||||
正则
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NSpace>
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 最大队列长度 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.queueMaxSize" :disabled="!configCanEdit" min="0" max="1000" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.queueMaxSize"
|
||||
:disabled="!configCanEdit"
|
||||
min="0"
|
||||
max="1000"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.enableOnStreaming" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableOnStreaming"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
仅在直播时才允许加入
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowAllDanmaku" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowAllDanmaku"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许所有用户加入
|
||||
</NCheckbox>
|
||||
<template v-if="!settings.allowAllDanmaku">
|
||||
<NInputGroup style="width: 270px">
|
||||
<NInputGroupLabel> 最低粉丝牌等级 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.fanMedalMinLevel" :disabled="!configCanEdit" min="0" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.fanMedalMinLevel"
|
||||
:disabled="!configCanEdit"
|
||||
min="0"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needJianzhang"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needJianzhang"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许舰长
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needTidu"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needTidu"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许提督
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needZongdu"
|
||||
@update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needZongdu"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许总督
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NSpace>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.allowGift" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowGift"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许通过发送礼物加入队列
|
||||
</NCheckbox>
|
||||
<template v-if="settings.allowGift">
|
||||
<NInputGroup v-if="settings.allowGift" style="width: 250px">
|
||||
<NInputGroup
|
||||
v-if="settings.allowGift"
|
||||
style="width: 250px"
|
||||
>
|
||||
<NInputGroupLabel> 最低价格 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.minGiftPrice" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.minGiftPrice"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NSpace align="center">
|
||||
礼物名
|
||||
<NSelect style="width: 250px" v-model:value="settings.giftNames" :disabled="!configCanEdit" filterable
|
||||
multiple tag placeholder="礼物名称,按回车确认" :show-arrow="false" :show="false"
|
||||
@update:value="updateSettings" />
|
||||
<NSelect
|
||||
v-model:value="settings.giftNames"
|
||||
style="width: 250px"
|
||||
:disabled="!configCanEdit"
|
||||
filterable
|
||||
multiple
|
||||
tag
|
||||
placeholder="礼物名称,按回车确认"
|
||||
:show-arrow="false"
|
||||
:show="false"
|
||||
@update:value="updateSettings"
|
||||
/>
|
||||
</NSpace>
|
||||
<span>
|
||||
<NRadioGroup v-model:value="settings.giftFilterType" :disabled="!configCanEdit"
|
||||
@update:value="updateSettings">
|
||||
<NRadioGroup
|
||||
v-model:value="settings.giftFilterType"
|
||||
:disabled="!configCanEdit"
|
||||
@update:value="updateSettings"
|
||||
>
|
||||
<NRadioButton :value="QueueGiftFilterType.And"> 需同时满足礼物名和价格 </NRadioButton>
|
||||
<NRadioButton :value="QueueGiftFilterType.Or"> 礼物名/价格 二选一 </NRadioButton>
|
||||
</NRadioGroup>
|
||||
</span>
|
||||
<NCheckbox v-model:checked="settings.sendGiftDirectJoin" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.sendGiftDirectJoin"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
赠送礼物后自动加入队列
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
@@ -1084,78 +1342,152 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
</NCheckbox>
|
||||
|
||||
<NCheckbox v-model:checked="settings.sendGiftIgnoreLimit" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.sendGiftIgnoreLimit"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
赠送礼物后无视用户等级限制
|
||||
</NCheckbox>
|
||||
</template>
|
||||
<NCheckbox v-model:checked="settings.allowIncreasePaymentBySendGift" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowIncreasePaymentBySendGift"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
在队列中时允许继续发送礼物累计付费量 (仅限上方设定的礼物)
|
||||
</NCheckbox>
|
||||
<NCheckbox v-if="settings.allowIncreasePaymentBySendGift"
|
||||
v-model:checked="settings.allowIncreaseByAnyPayment" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-if="settings.allowIncreasePaymentBySendGift"
|
||||
v-model:checked="settings.allowIncreaseByAnyPayment"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
允许发送任意礼物来叠加付费量
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 冷却 (单位: 秒) </NDivider>
|
||||
<NCheckbox v-model:checked="settings.enableCooldown" @update:checked="updateSettings"
|
||||
:disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableCooldown"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
启用排队冷却
|
||||
</NCheckbox>
|
||||
<NSpace v-if="settings.enableCooldown">
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 普通弹幕 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.cooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.cooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 舰长 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.jianzhangCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.jianzhangCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 提督 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.tiduCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.tiduCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="width: 220px">
|
||||
<NInputGroupLabel> 总督 </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.zongduCooldownSecond" :disabled="!configCanEdit" />
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
<NInputNumber
|
||||
v-model:value="settings.zongduCooldownSecond"
|
||||
:disabled="!configCanEdit"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:disabled="!configCanEdit"
|
||||
@click="updateSettings"
|
||||
>
|
||||
确定
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NDivider> OBS </NDivider>
|
||||
<NCheckbox v-model:checked="settings.showRequireInfo" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showRequireInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示底部的需求信息
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showPayment" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showPayment"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示付费信息
|
||||
</NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showFanMadelInfo" :disabled="!configCanEdit"
|
||||
@update:checked="updateSettings">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showFanMadelInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示用户粉丝牌
|
||||
</NCheckbox>
|
||||
<NDivider> 其他 </NDivider>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose"> 自动关闭加入队列失败时的提示消息 </NCheckbox>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose">
|
||||
自动关闭加入队列失败时的提示消息
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
</NSpin>
|
||||
</NTabPane>
|
||||
</NTabs>
|
||||
<template v-else>
|
||||
<NAlert title="未启用" type="error"> 请先启用弹幕排队功能 </NAlert>
|
||||
<NAlert
|
||||
title="未启用"
|
||||
type="error"
|
||||
>
|
||||
请先启用弹幕排队功能
|
||||
</NAlert>
|
||||
</template>
|
||||
</NCard>
|
||||
<NModal v-model:show="showOBSModal" title="OBS组件" preset="card" style="width: 800px">
|
||||
<NAlert title="这是什么? " type="info"> 将等待队列以及结果显示在OBS中 </NAlert>
|
||||
<NModal
|
||||
v-model:show="showOBSModal"
|
||||
title="OBS组件"
|
||||
preset="card"
|
||||
style="width: 800px"
|
||||
>
|
||||
<NAlert
|
||||
title="这是什么? "
|
||||
type="info"
|
||||
>
|
||||
将等待队列以及结果显示在OBS中
|
||||
</NAlert>
|
||||
<NDivider> 浏览 </NDivider>
|
||||
<div style="height: 500px; width: 280px; position: relative; margin: 0 auto">
|
||||
<QueueOBS :id="accountInfo?.id" />
|
||||
</div>
|
||||
<br />
|
||||
<br>
|
||||
<NInput :value="`${CURRENT_HOST}obs/queue?id=` + accountInfo?.id" />
|
||||
<NDivider />
|
||||
<NCollapse>
|
||||
|
||||
@@ -585,60 +585,110 @@ onUnmounted(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NAlert v-if="!speechSynthesisInfo || !speechSynthesisInfo.speechSynthesis" type="error">
|
||||
<NAlert
|
||||
v-if="!speechSynthesisInfo || !speechSynthesisInfo.speechSynthesis"
|
||||
type="error"
|
||||
>
|
||||
你的浏览器不支持语音功能
|
||||
</NAlert>
|
||||
<template v-else>
|
||||
<NSpace vertical>
|
||||
<NAlert v-if="settings.voiceType == 'local'" type="info" closeable>
|
||||
<NAlert
|
||||
v-if="settings.voiceType == 'local'"
|
||||
type="info"
|
||||
closeable
|
||||
>
|
||||
建议在 Edge 浏览器使用
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText strong italic type="primary">Microsoft 某某 Online (Nature)</NText>
|
||||
<NText
|
||||
strong
|
||||
italic
|
||||
type="primary"
|
||||
>
|
||||
Microsoft 某某 Online (Nature)
|
||||
</NText>
|
||||
</template>
|
||||
例如 Microsoft Xiaoxiao Online (Natural) - Chinese (Mainland), 各种营销号就用的这些配音
|
||||
</NTooltip>
|
||||
系列语音, 效果要好
|
||||
<NText strong>很多很多</NText>
|
||||
<NText strong>
|
||||
很多很多
|
||||
</NText>
|
||||
</NAlert>
|
||||
<NAlert type="info" closeable>
|
||||
<NAlert
|
||||
type="info"
|
||||
closeable
|
||||
>
|
||||
当在后台运行时请关闭浏览器的 页面休眠/内存节省功能. Chrome:
|
||||
<NButton tag="a" type="info"
|
||||
<NButton
|
||||
tag="a"
|
||||
type="info"
|
||||
href="https://support.google.com/chrome/answer/12929150?hl=zh-Hans#zippy=%2C%E5%BC%80%E5%90%AF%E6%88%96%E5%85%B3%E9%97%AD%E7%9C%81%E5%86%85%E5%AD%98%E6%A8%A1%E5%BC%8F%2C%E8%AE%A9%E7%89%B9%E5%AE%9A%E7%BD%91%E7%AB%99%E4%BF%9D%E6%8C%81%E6%B4%BB%E5%8A%A8%E7%8A%B6%E6%80%81"
|
||||
target="_blank" text>
|
||||
target="_blank"
|
||||
text
|
||||
>
|
||||
让特定网站保持活动状态
|
||||
</NButton>
|
||||
Edge:
|
||||
|
||||
<NButton tag="a" type="info"
|
||||
<NButton
|
||||
tag="a"
|
||||
type="info"
|
||||
href="https://support.microsoft.com/zh-cn/topic/%E4%BA%86%E8%A7%A3-microsoft-edge-%E4%B8%AD%E7%9A%84%E6%80%A7%E8%83%BD%E5%8A%9F%E8%83%BD-7b36f363-2119-448a-8de6-375cfd88ab25"
|
||||
target="_blank" text>
|
||||
target="_blank"
|
||||
text
|
||||
>
|
||||
永远不想进入睡眠状态的网站
|
||||
</NButton>
|
||||
</NAlert>
|
||||
</NSpace>
|
||||
<br />
|
||||
<br>
|
||||
<NSpace align="center">
|
||||
<NButton @click="canSpeech ? stopSpeech() : startSpeech()" :type="canSpeech ? 'error' : 'primary'"
|
||||
data-umami-event="Use TTS" :data-umami-event-uid="accountInfo?.id" size="large">
|
||||
<NButton
|
||||
:type="canSpeech ? 'error' : 'primary'"
|
||||
data-umami-event="Use TTS"
|
||||
:data-umami-event-uid="accountInfo?.id"
|
||||
size="large"
|
||||
@click="canSpeech ? stopSpeech() : startSpeech()"
|
||||
>
|
||||
{{ canSpeech ? '停止监听' : '开始监听' }}
|
||||
</NButton>
|
||||
<NButton @click="uploadConfig" type="primary" secondary :disabled="!accountInfo" size="small">
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
:disabled="!accountInfo"
|
||||
size="small"
|
||||
@click="uploadConfig"
|
||||
>
|
||||
保存配置到服务器
|
||||
</NButton>
|
||||
<NPopconfirm @positive-click="downloadConfig">
|
||||
<template #trigger>
|
||||
<NButton type="primary" secondary :disabled="!accountInfo" size="small"> 从服务器获取配置 </NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
:disabled="!accountInfo"
|
||||
size="small"
|
||||
>
|
||||
从服务器获取配置
|
||||
</NButton>
|
||||
</template>
|
||||
这将覆盖当前设置, 确定?
|
||||
</NPopconfirm>
|
||||
</NSpace>
|
||||
<template v-if="canSpeech">
|
||||
<NDivider> 状态 </NDivider>
|
||||
<NSpace vertical align="center">
|
||||
<NSpace
|
||||
vertical
|
||||
align="center"
|
||||
>
|
||||
<NTooltip v-if="settings.voiceType == 'api' && isApiAudioLoading">
|
||||
<template #trigger>
|
||||
<NButton circle @click="cancelSpeech">
|
||||
<NButton
|
||||
circle
|
||||
@click="cancelSpeech"
|
||||
>
|
||||
<template #icon>
|
||||
<NSpin show />
|
||||
</template>
|
||||
@@ -648,40 +698,96 @@ onUnmounted(() => {
|
||||
</NTooltip>
|
||||
<NTooltip v-else>
|
||||
<template #trigger>
|
||||
<NButton circle :disabled="!isSpeaking" @click="cancelSpeech"
|
||||
:style="`animation: ${isSpeaking ? 'animated-border 2.5s infinite;' : ''}`">
|
||||
<NButton
|
||||
circle
|
||||
:disabled="!isSpeaking"
|
||||
:style="`animation: ${isSpeaking ? 'animated-border 2.5s infinite;' : ''}`"
|
||||
@click="cancelSpeech"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Mic24Filled" :color="isSpeaking ? 'green' : 'gray'" />
|
||||
<NIcon
|
||||
:component="Mic24Filled"
|
||||
:color="isSpeaking ? 'green' : 'gray'"
|
||||
/>
|
||||
</template>
|
||||
</NButton>
|
||||
</template>
|
||||
{{ isSpeaking ? '取消朗读' : '未朗读' }}
|
||||
</NTooltip>
|
||||
<NText depth="3"> 队列: {{ speakQueue.length }}
|
||||
<NText depth="3">
|
||||
队列: {{ speakQueue.length }}
|
||||
<NDivider vertical /> 已读: {{ readedDanmaku }} 条
|
||||
</NText>
|
||||
<NCollapse :default-expanded-names="['1']">
|
||||
<NCollapseItem title="队列" name="1">
|
||||
<NEmpty v-if="speakQueue.length == 0"> 暂无 </NEmpty>
|
||||
<NList v-else size="small" bordered>
|
||||
<NListItem v-for="item in speakQueue" :key="item.data.time">
|
||||
<NCollapseItem
|
||||
title="队列"
|
||||
name="1"
|
||||
>
|
||||
<NEmpty v-if="speakQueue.length == 0">
|
||||
暂无
|
||||
</NEmpty>
|
||||
<NList
|
||||
v-else
|
||||
size="small"
|
||||
bordered
|
||||
>
|
||||
<NListItem
|
||||
v-for="item in speakQueue"
|
||||
:key="item.data.time"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<NButton @click="forceSpeak(item.data)" type="primary" secondary size="small"> 读 </NButton>
|
||||
<NButton @click="speakQueue.splice(speakQueue.indexOf(item), 1)" type="error" secondary size="small">
|
||||
<NButton
|
||||
type="primary"
|
||||
secondary
|
||||
size="small"
|
||||
@click="forceSpeak(item.data)"
|
||||
>
|
||||
读
|
||||
</NButton>
|
||||
<NButton
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
@click="speakQueue.splice(speakQueue.indexOf(item), 1)"
|
||||
>
|
||||
取消
|
||||
</NButton>
|
||||
<NTag v-if="item.data.type == EventDataTypes.Gift && item.combineCount" type="info" size="small"
|
||||
style="animation: animated-border 2.5s infinite">
|
||||
连续赠送中</NTag>
|
||||
<NTag v-else-if="item.data.type == EventDataTypes.Gift && settings.combineGiftDelay" type="success"
|
||||
size="small">
|
||||
<NTag
|
||||
v-if="item.data.type == EventDataTypes.Gift && item.combineCount"
|
||||
type="info"
|
||||
size="small"
|
||||
style="animation: animated-border 2.5s infinite"
|
||||
>
|
||||
连续赠送中
|
||||
</NTag>
|
||||
<NTag
|
||||
v-else-if="item.data.type == EventDataTypes.Gift && settings.combineGiftDelay"
|
||||
type="success"
|
||||
size="small"
|
||||
>
|
||||
等待连续赠送检查
|
||||
</NTag>
|
||||
<span>
|
||||
<NTag v-if="item.data.type == EventDataTypes.Message" type="success" size="small"> 弹幕</NTag>
|
||||
<NTag v-else-if="item.data.type == EventDataTypes.Gift" type="success" size="small"> 礼物</NTag>
|
||||
<NTag v-else-if="item.data.type == EventDataTypes.Guard" type="success" size="small"> 舰长</NTag>
|
||||
<NTag v-else-if="item.data.type == EventDataTypes.SC" type="success" size="small"> SC</NTag>
|
||||
<NTag
|
||||
v-if="item.data.type == EventDataTypes.Message"
|
||||
type="success"
|
||||
size="small"
|
||||
> 弹幕</NTag>
|
||||
<NTag
|
||||
v-else-if="item.data.type == EventDataTypes.Gift"
|
||||
type="success"
|
||||
size="small"
|
||||
> 礼物</NTag>
|
||||
<NTag
|
||||
v-else-if="item.data.type == EventDataTypes.Guard"
|
||||
type="success"
|
||||
size="small"
|
||||
> 舰长</NTag>
|
||||
<NTag
|
||||
v-else-if="item.data.type == EventDataTypes.SC"
|
||||
type="success"
|
||||
size="small"
|
||||
> SC</NTag>
|
||||
</span>
|
||||
<NText>
|
||||
{{ item.data.name }}
|
||||
@@ -697,8 +803,13 @@ onUnmounted(() => {
|
||||
</NSpace>
|
||||
</template>
|
||||
<NDivider>
|
||||
<NRadioGroup v-model:value="settings.voiceType" size="small">
|
||||
<NRadioButton value="local">本地</NRadioButton>
|
||||
<NRadioGroup
|
||||
v-model:value="settings.voiceType"
|
||||
size="small"
|
||||
>
|
||||
<NRadioButton value="local">
|
||||
本地
|
||||
</NRadioButton>
|
||||
<NRadioButton value="api">
|
||||
API
|
||||
|
||||
@@ -711,27 +822,57 @@ onUnmounted(() => {
|
||||
</NRadioButton>
|
||||
</NRadioGroup>
|
||||
</NDivider>
|
||||
<Transition name="fade" mode="out-in">
|
||||
<NSpace v-if="settings.voiceType == 'local'" vertical>
|
||||
<NSelect v-model:value="settings.speechInfo.voice" :options="voiceOptions"
|
||||
:fallback-option="() => ({ label: '未选择, 将使用默认语音', value: '' })" />
|
||||
<Transition
|
||||
name="fade"
|
||||
mode="out-in"
|
||||
>
|
||||
<NSpace
|
||||
v-if="settings.voiceType == 'local'"
|
||||
vertical
|
||||
>
|
||||
<NSelect
|
||||
v-model:value="settings.speechInfo.voice"
|
||||
:options="voiceOptions"
|
||||
:fallback-option="() => ({ label: '未选择, 将使用默认语音', value: '' })"
|
||||
/>
|
||||
<span style="width: 100%">
|
||||
<NText> 音量 </NText>
|
||||
<NSlider style="min-width: 200px" v-model:value="settings.speechInfo.volume" :min="0" :max="1" :step="0.01" />
|
||||
<NSlider
|
||||
v-model:value="settings.speechInfo.volume"
|
||||
style="min-width: 200px"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
/>
|
||||
</span>
|
||||
<span style="width: 100%">
|
||||
<NText> 音调 </NText>
|
||||
<NSlider style="min-width: 200px" v-model:value="settings.speechInfo.pitch" :min="0" :max="2" :step="0.01" />
|
||||
<NSlider
|
||||
v-model:value="settings.speechInfo.pitch"
|
||||
style="min-width: 200px"
|
||||
:min="0"
|
||||
:max="2"
|
||||
:step="0.01"
|
||||
/>
|
||||
</span>
|
||||
<span style="width: 100%">
|
||||
<NText> 语速 </NText>
|
||||
<NSlider style="min-width: 200px" v-model:value="settings.speechInfo.rate" :min="0" :max="2" :step="0.01" />
|
||||
<NSlider
|
||||
v-model:value="settings.speechInfo.rate"
|
||||
style="min-width: 200px"
|
||||
:min="0"
|
||||
:max="2"
|
||||
:step="0.01"
|
||||
/>
|
||||
</span>
|
||||
</NSpace>
|
||||
<template v-else>
|
||||
<div>
|
||||
<NCollapse>
|
||||
<NCollapseItem title="要求 👀 " name="1">
|
||||
<NCollapseItem
|
||||
title="要求 👀 "
|
||||
name="1"
|
||||
>
|
||||
<NUl>
|
||||
<NLi> 直接返回音频数据 (wav, mp3, m4a etc.) </NLi>
|
||||
<NLi>
|
||||
@@ -746,49 +887,88 @@ onUnmounted(() => {
|
||||
<NLi> 指定API可以被外部访问 (除非你本地部署并且启用了https) </NLi>
|
||||
</NUl>
|
||||
推荐项目, 可以用于本地部署:
|
||||
<NButton text type="info" tag="a" href="https://github.com/Artrajz/vits-simple-api" target="_blank">
|
||||
<NButton
|
||||
text
|
||||
type="info"
|
||||
tag="a"
|
||||
href="https://github.com/Artrajz/vits-simple-api"
|
||||
target="_blank"
|
||||
>
|
||||
vits-simple-api
|
||||
</NButton>
|
||||
</NCollapseItem>
|
||||
</NCollapse>
|
||||
<br />
|
||||
<br>
|
||||
<NSpace vertical>
|
||||
<NAlert type="info">
|
||||
地址中的
|
||||
<NButton @click="copyToClipboard('{{text}}')" size="tiny" :bordered="false" type="primary" secondary>
|
||||
<NButton
|
||||
size="tiny"
|
||||
:bordered="false"
|
||||
type="primary"
|
||||
secondary
|
||||
@click="copyToClipboard('{{text}}')"
|
||||
>
|
||||
{{ '\{\{ text \}\}' }}
|
||||
</NButton>
|
||||
将被替换为要念的文本
|
||||
</NAlert>
|
||||
<NAlert v-if="isVtsuruVoiceAPI" type="success" closable>
|
||||
<NAlert
|
||||
v-if="isVtsuruVoiceAPI"
|
||||
type="success"
|
||||
closable
|
||||
>
|
||||
看起来你正在使用本站提供的测试API (voice.vtsuru.live), 这个接口将会返回
|
||||
<NButton text type="info" tag="a" href="https://space.bilibili.com/5859321" target="_blank">
|
||||
<NButton
|
||||
text
|
||||
type="info"
|
||||
tag="a"
|
||||
href="https://space.bilibili.com/5859321"
|
||||
target="_blank"
|
||||
>
|
||||
Xz乔希
|
||||
</NButton>
|
||||
训练的
|
||||
<NTooltip>
|
||||
<template #trigger> Taffy </template>
|
||||
<template #trigger>
|
||||
Taffy
|
||||
</template>
|
||||
链接里的 id 改成 0 会变成莲莲捏🥰
|
||||
</NTooltip>
|
||||
模型结果, 不支持部分英文, 仅用于测试, 用的人多的时候会比较慢, 不保证可用性. 侵删
|
||||
</NAlert>
|
||||
</NSpace>
|
||||
<br />
|
||||
<br>
|
||||
<NInputGroup>
|
||||
<NSelect v-model:value="settings.voiceAPISchemeType" :options="[
|
||||
{ label: 'https://', value: 'https' },
|
||||
{ label: 'http://', value: 'http' },
|
||||
]" style="width: 110px" />
|
||||
<NInput v-model:value="settings.voiceAPI"
|
||||
<NSelect
|
||||
v-model:value="settings.voiceAPISchemeType"
|
||||
:options="[
|
||||
{ label: 'https://', value: 'https' },
|
||||
{ label: 'http://', value: 'http' },
|
||||
]"
|
||||
style="width: 110px"
|
||||
/>
|
||||
<NInput
|
||||
v-model:value="settings.voiceAPI"
|
||||
placeholder="API 地址, 例如 xxx.com/voice/bert-vits2?text={{text}}&id=0 (前面不要带https://)"
|
||||
:status="/^(?:https?:\/\/)/.test(settings.voiceAPI?.toLowerCase() ?? '') ? 'error' : 'success'" />
|
||||
<NButton @click="testAPI" type="info" :loading="isApiAudioLoading"> 测试 </NButton>
|
||||
:status="/^(?:https?:\/\/)/.test(settings.voiceAPI?.toLowerCase() ?? '') ? 'error' : 'success'"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isApiAudioLoading"
|
||||
@click="testAPI"
|
||||
>
|
||||
测试
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<br /><br />
|
||||
<br><br>
|
||||
<NSpace vertical>
|
||||
<NAlert v-if="settings.voiceAPISchemeType == 'http'" type="info">
|
||||
<NAlert
|
||||
v-if="settings.voiceAPISchemeType == 'http'"
|
||||
type="info"
|
||||
>
|
||||
不使用https的话默认将会使用 cloudflare workers 进行代理, 会慢很多
|
||||
<br />
|
||||
<br>
|
||||
<NCheckbox v-model:checked="settings.useAPIDirectly">
|
||||
不使用代理
|
||||
<NTooltip>
|
||||
@@ -801,12 +981,23 @@ onUnmounted(() => {
|
||||
</NAlert>
|
||||
<span style="width: 100%">
|
||||
<NText> 音量 </NText>
|
||||
<NSlider style="min-width: 200px" v-model:value="settings.speechInfo.volume" :min="0" :max="1"
|
||||
:step="0.01" />
|
||||
<NSlider
|
||||
v-model:value="settings.speechInfo.volume"
|
||||
style="min-width: 200px"
|
||||
:min="0"
|
||||
:max="1"
|
||||
:step="0.01"
|
||||
/>
|
||||
</span>
|
||||
</NSpace>
|
||||
<audio ref="apiAudio" :src="apiAudioSrc" :volume="settings.speechInfo.volume" @ended="cancelSpeech"
|
||||
@canplay="isApiAudioLoading = false" @error="onAPIError"></audio>
|
||||
<audio
|
||||
ref="apiAudio"
|
||||
:src="apiAudioSrc"
|
||||
:volume="settings.speechInfo.volume"
|
||||
@ended="cancelSpeech"
|
||||
@canplay="isApiAudioLoading = false"
|
||||
@error="onAPIError"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Transition>
|
||||
@@ -822,54 +1013,104 @@ onUnmounted(() => {
|
||||
<NSpace vertical>
|
||||
<NSpace>
|
||||
支持的变量:
|
||||
<NButton size="tiny" secondary v-for="item in Object.values(templateConstants)" :key="item.name"
|
||||
@click="copyToClipboard(item.words)">
|
||||
<NButton
|
||||
v-for="item in Object.values(templateConstants)"
|
||||
:key="item.name"
|
||||
size="tiny"
|
||||
secondary
|
||||
@click="copyToClipboard(item.words)"
|
||||
>
|
||||
{{ item.words }} | {{ item.name }}
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NInputGroup>
|
||||
<NInputGroupLabel> 弹幕模板 </NInputGroupLabel>
|
||||
<NInput v-model:value="settings.danmakuTemplate" placeholder="弹幕消息" />
|
||||
<NButton @click="test(EventDataTypes.Message)" type="info" :loading="isApiAudioLoading"> 测试 </NButton>
|
||||
<NInput
|
||||
v-model:value="settings.danmakuTemplate"
|
||||
placeholder="弹幕消息"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isApiAudioLoading"
|
||||
@click="test(EventDataTypes.Message)"
|
||||
>
|
||||
测试
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup>
|
||||
<NInputGroupLabel> 礼物模板 </NInputGroupLabel>
|
||||
<NInput v-model:value="settings.giftTemplate" placeholder="礼物消息" />
|
||||
<NButton @click="test(EventDataTypes.Gift)" type="info" :loading="isApiAudioLoading"> 测试 </NButton>
|
||||
<NInput
|
||||
v-model:value="settings.giftTemplate"
|
||||
placeholder="礼物消息"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isApiAudioLoading"
|
||||
@click="test(EventDataTypes.Gift)"
|
||||
>
|
||||
测试
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup>
|
||||
<NInputGroupLabel> SC模板 </NInputGroupLabel>
|
||||
<NInput v-model:value="settings.scTemplate" placeholder="SC消息" />
|
||||
<NButton @click="test(EventDataTypes.SC)" type="info" :loading="isApiAudioLoading"> 测试 </NButton>
|
||||
<NInput
|
||||
v-model:value="settings.scTemplate"
|
||||
placeholder="SC消息"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isApiAudioLoading"
|
||||
@click="test(EventDataTypes.SC)"
|
||||
>
|
||||
测试
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
<NInputGroup>
|
||||
<NInputGroupLabel> 上舰模板 </NInputGroupLabel>
|
||||
<NInput v-model:value="settings.guardTemplate" placeholder="上舰消息" />
|
||||
<NButton @click="test(EventDataTypes.Guard)" type="info" :loading="isApiAudioLoading"> 测试 </NButton>
|
||||
<NInput
|
||||
v-model:value="settings.guardTemplate"
|
||||
placeholder="上舰消息"
|
||||
/>
|
||||
<NButton
|
||||
type="info"
|
||||
:loading="isApiAudioLoading"
|
||||
@click="test(EventDataTypes.Guard)"
|
||||
>
|
||||
测试
|
||||
</NButton>
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NDivider> 设置 </NDivider>
|
||||
<NSpace align="center">
|
||||
<NCheckbox :checked="settings.combineGiftDelay != undefined" @update:checked="(checked: boolean) => {
|
||||
settings.combineGiftDelay = checked ? 2 : undefined
|
||||
}
|
||||
">
|
||||
<NCheckbox
|
||||
:checked="settings.combineGiftDelay != undefined"
|
||||
@update:checked="(checked: boolean) => {
|
||||
settings.combineGiftDelay = checked ? 2 : undefined
|
||||
}
|
||||
"
|
||||
>
|
||||
是否启用礼物合并
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
在指定时间内连续送相同礼物会等停止送礼物之后才会念
|
||||
<br />
|
||||
<br>
|
||||
这也会导致送的礼物会等待指定时间之后才会念, 即使没有连续赠送
|
||||
</NTooltip>
|
||||
</NCheckbox>
|
||||
<NInputGroup v-if="settings.combineGiftDelay" style="width: 200px">
|
||||
<NInputGroup
|
||||
v-if="settings.combineGiftDelay"
|
||||
style="width: 200px"
|
||||
>
|
||||
<NInputGroupLabel> 送礼间隔 (秒) </NInputGroupLabel>
|
||||
<NInputNumber v-model:value="settings.combineGiftDelay" @update:value="(value) => {
|
||||
if (!value || value <= 0) settings.combineGiftDelay = undefined
|
||||
}
|
||||
" />
|
||||
<NInputNumber
|
||||
v-model:value="settings.combineGiftDelay"
|
||||
@update:value="(value) => {
|
||||
if (!value || value <= 0) settings.combineGiftDelay = undefined
|
||||
}
|
||||
"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-model:checked="settings.splitText">
|
||||
启用句子拆分
|
||||
@@ -878,9 +1119,9 @@ onUnmounted(() => {
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
仅API方式可用, 为英文用户名用引号包裹起来, 并将所有大写单词拆分成单个单词, 以防止部分单词念不出来
|
||||
<br />
|
||||
<br>
|
||||
例: 原文: Megghy 说: UPPERCASE单词,word.
|
||||
<br />
|
||||
<br>
|
||||
结果: 'Megghy' 说: U P P E R C A S E 单词,word.
|
||||
</NTooltip>
|
||||
</NCheckbox>
|
||||
|
||||
Reference in New Issue
Block a user