mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-10 20:36:55 +08:00
add switch
This commit is contained in:
@@ -157,7 +157,9 @@ async function getNeteaseSongList() {
|
||||
.then((data) => {
|
||||
if (data.code == 200) {
|
||||
neteaseSongs.value = data.data
|
||||
message.success(`成功获取歌曲信息, 共 ${data.data.length} 条, 歌单中已存在 ${neteaseSongsOptions.value.filter((s) => s.disabled).length} 首`)
|
||||
message.success(
|
||||
`成功获取歌曲信息, 共 ${data.data.length} 条, 歌单中已存在 ${neteaseSongsOptions.value.filter((s) => s.disabled).length} 首`,
|
||||
)
|
||||
} else {
|
||||
message.error('获取歌单失败: ' + data.message)
|
||||
}
|
||||
@@ -278,7 +280,9 @@ async function onGetEvent(data: EventModel) {
|
||||
if (settings.value.orderCooldown && cooldown.value[data.uid] && data.uid != (accountInfo.value?.biliId ?? -1)) {
|
||||
const lastRequest = cooldown.value[data.uid]
|
||||
if (Date.now() - lastRequest < settings.value.orderCooldown * 1000) {
|
||||
message.info(`[${data.name}] 冷却中,距离下次点歌还有 ${((settings.value.orderCooldown * 1000 - (Date.now() - lastRequest)) / 1000).toFixed(1)} 秒`)
|
||||
message.info(
|
||||
`[${data.name}] 冷却中,距离下次点歌还有 ${((settings.value.orderCooldown * 1000 - (Date.now() - lastRequest)) / 1000).toFixed(1)} 秒`,
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -326,7 +330,9 @@ async function getOutputDevice() {
|
||||
})
|
||||
const list = await navigator.mediaDevices.enumerateDevices()
|
||||
|
||||
deviceList.value = list.filter((device) => device.kind === 'audiooutput').map((d) => ({ label: d.label, value: d.deviceId }))
|
||||
deviceList.value = list
|
||||
.filter((device) => device.kind === 'audiooutput')
|
||||
.map((d) => ({ label: d.label, value: d.deviceId }))
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
message.error('获取音频输出设备失败, 获取你需要授予网页读取麦克风权限: ' + err)
|
||||
@@ -393,7 +399,9 @@ onUnmounted(() => {
|
||||
<NButton @click="showOBSModal = true" type="info" size="small"> OBS组件 </NButton>
|
||||
<NButton @click="showNeteaseModal = true" size="small"> 从网易云歌单导入空闲歌单 </NButton>
|
||||
|
||||
<NButton @click="uploadConfig" type="primary" secondary :disabled="!accountInfo" size="small"> 保存配置到服务器 </NButton>
|
||||
<NButton @click="uploadConfig" type="primary" secondary :disabled="!accountInfo" size="small">
|
||||
保存配置到服务器
|
||||
</NButton>
|
||||
<NPopconfirm @positive-click="downloadConfig">
|
||||
<template #trigger>
|
||||
<NButton type="primary" secondary :disabled="!accountInfo" size="small"> 从服务器获取配置 </NButton>
|
||||
@@ -406,10 +414,19 @@ onUnmounted(() => {
|
||||
<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">
|
||||
<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>
|
||||
<NButton @click="musicRquestStore.waitingMusics.splice(musicRquestStore.waitingMusics.indexOf(item), 1)" type="error" secondary size="small"> 取消 </NButton>
|
||||
<NButton @click="musicRquestStore.playMusic(item.music)" type="primary" secondary size="small">
|
||||
播放
|
||||
</NButton>
|
||||
<NButton
|
||||
@click="musicRquestStore.waitingMusics.splice(musicRquestStore.waitingMusics.indexOf(item), 1)"
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
>
|
||||
取消
|
||||
</NButton>
|
||||
<NButton @click="blockMusic(item.music)" type="warning" secondary size="small"> 拉黑 </NButton>
|
||||
<span>
|
||||
<NTag v-if="item.music.from == SongFrom.Netease" type="success" size="small"> 网易</NTag>
|
||||
@@ -493,7 +510,7 @@ onUnmounted(() => {
|
||||
<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>
|
||||
<template #default="{ item, index }">
|
||||
<template #default="{ item }">
|
||||
<p :style="`min-height: ${30}px;width:97%;display:flex;align-items:center;`">
|
||||
<NSpace align="center" style="width: 100%">
|
||||
<NPopconfirm @positive-click="delMusic(item)">
|
||||
@@ -512,9 +529,16 @@ onUnmounted(() => {
|
||||
</NTabPane>
|
||||
<NTabPane name="blacklist" tab="黑名单">
|
||||
<NList>
|
||||
<NListItem v-for="item in settings.blacklist">
|
||||
<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"> 删除 </NButton>
|
||||
<NButton
|
||||
@click="settings.blacklist.splice(settings.blacklist.indexOf(item), 1)"
|
||||
type="error"
|
||||
secondary
|
||||
size="small"
|
||||
>
|
||||
删除
|
||||
</NButton>
|
||||
<NText> {{ item }} </NText>
|
||||
</NSpace>
|
||||
</NListItem>
|
||||
@@ -523,18 +547,35 @@ onUnmounted(() => {
|
||||
</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或者网页链接">
|
||||
<NInput
|
||||
clearable
|
||||
style="width: 100%"
|
||||
autosize
|
||||
:status="neteaseSongListId ? 'success' : 'error'"
|
||||
v-model:value="neteaseIdInput"
|
||||
placeholder="直接输入歌单Id或者网页链接"
|
||||
>
|
||||
<template #suffix>
|
||||
<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>
|
||||
<NButton type="primary" @click="getNeteaseSongList" :disabled="!neteaseSongListId" :loading="isLoading">
|
||||
获取
|
||||
</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
|
||||
style="height: 500px"
|
||||
ref="transfer"
|
||||
v-model:value="selectedNeteaseSongs"
|
||||
:options="neteaseSongsOptions"
|
||||
source-filterable
|
||||
/>
|
||||
<NDivider style="margin: 10px" />
|
||||
<NButton type="primary" @click="addNeteaseSongs" :loading="isLoading"> 添加到歌单 | {{ selectedNeteaseSongs.length }} 首 </NButton>
|
||||
<NButton type="primary" @click="addNeteaseSongs" :loading="isLoading">
|
||||
添加到歌单 | {{ selectedNeteaseSongs.length }} 首
|
||||
</NButton>
|
||||
</template>
|
||||
</NModal>
|
||||
<NModal v-model:show="showOBSModal" title="OBS组件" preset="card" style="width: 800px">
|
||||
|
||||
@@ -18,37 +18,60 @@ const accountInfo = useAccount()
|
||||
<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>
|
||||
<NButton @click="$router.push({ name: 'open-live-lottery', query: $route.query })" type="primary">
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
<NCard hoverable embedded size="small" title="弹幕点歌" style="width: 300px">
|
||||
通过弹幕或者SC进行点歌, 注册后可以保存和导出 (这个是歌势用的点歌, 不是拿来放歌的那种!)
|
||||
<template #footer>
|
||||
<NButton @click="$router.push({ name: 'open-live-song-request', query: $route.query })" type="primary"> 前往使用 </NButton>
|
||||
<NButton @click="$router.push({ name: 'open-live-song-request', query: $route.query })" type="primary">
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
<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>
|
||||
<NButton @click="$router.push({ name: 'open-live-queue', query: $route.query })" type="primary">
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
|
||||
<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>
|
||||
<NButton @click="$router.push({ name: 'open-live-speech', query: $route.query })" type="primary">
|
||||
前往使用
|
||||
</NButton>
|
||||
</template>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
<br />
|
||||
<NAlert v-if="accountInfo?.eventFetcherOnline != true" type="warning" title="可用性警告" style="max-width: 600px; margin: 0 auto">
|
||||
<NAlert
|
||||
v-if="accountInfo?.eventFetcherOnline != 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>), 虽然本站已经针对此问题做出了处理, 一般情况下即使掉线了也会重连,
|
||||
不过还是有可能会遗漏事件
|
||||
<NButton text tag="a" href="https://developer.chrome.com/blog/background_tabs/" target="_blank" type="info"
|
||||
>此文章</NButton
|
||||
>), 虽然本站已经针对此问题做出了处理, 一般情况下即使掉线了也会重连, 不过还是有可能会遗漏事件
|
||||
<br />
|
||||
为避免这种情况, 建议注册本站账后使用 <NButton type="primary" text size="tiny" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank"> VtsuruEventFetcher </NButton>,
|
||||
否则请在使用功能时尽量保持网页在前台运行
|
||||
为避免这种情况, 建议注册本站账后使用
|
||||
<NButton
|
||||
type="primary"
|
||||
text
|
||||
size="tiny"
|
||||
tag="a"
|
||||
href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p"
|
||||
target="_blank"
|
||||
>
|
||||
VtsuruEventFetcher </NButton
|
||||
>, 否则请在使用功能时尽量保持网页在前台运行
|
||||
</NAlert>
|
||||
<NDivider> 还有更多 </NDivider>
|
||||
<NSpace justify="center" align="center" vertical>
|
||||
|
||||
@@ -178,7 +178,10 @@ function startLottery() {
|
||||
removeSingleUser()
|
||||
function removeSingleUser() {
|
||||
if (currentUsers.value.length > lotteryOption.value.resultCount) {
|
||||
console.log(`[${currentUsers.value.length}] 移除` + currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name)
|
||||
console.log(
|
||||
`[${currentUsers.value.length}] 移除` +
|
||||
currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name,
|
||||
)
|
||||
setTimeout(() => {
|
||||
removeSingleUser()
|
||||
}, 500)
|
||||
@@ -193,7 +196,10 @@ function startLottery() {
|
||||
if (currentUsers.value.length / 2 <= lotteryOption.value.resultCount) {
|
||||
console.log(`[OPEN-LIVE-Lottery] 人数减半至${lotteryOption.value.resultCount}人`)
|
||||
while (currentUsers.value.length > lotteryOption.value.resultCount) {
|
||||
console.log(`[${currentUsers.value.length}] 移除` + currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name)
|
||||
console.log(
|
||||
`[${currentUsers.value.length}] 移除` +
|
||||
currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name,
|
||||
)
|
||||
}
|
||||
onFinishLottery()
|
||||
} else {
|
||||
@@ -201,7 +207,10 @@ function startLottery() {
|
||||
console.log(`[OPEN-LIVE-Lottery] 人数减半至${half}人`)
|
||||
message.success('人数减半至 ' + half + ' 人')
|
||||
while (currentUsers.value.length > half) {
|
||||
console.log(`[${currentUsers.value.length}] 移除` + currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name)
|
||||
console.log(
|
||||
`[${currentUsers.value.length}] 移除` +
|
||||
currentUsers.value.splice(getRandomInt(currentUsers.value.length), 1)[0].name,
|
||||
)
|
||||
}
|
||||
}
|
||||
isLottering.value = false
|
||||
@@ -224,10 +233,13 @@ function onFinishLottery() {
|
||||
description: '共' + resultUsers.value?.length + '人',
|
||||
duration: 3000,
|
||||
content: () =>
|
||||
h(
|
||||
NSpace,
|
||||
{ vertical: true },
|
||||
() => resultUsers.value?.map((user) => h(NSpace, null, () => [h(NAvatar, { src: user.avatar + '@32w_32h', imgProps: { referrerpolicy: 'no-referrer' } }), h('span', user.name)])),
|
||||
h(NSpace, { vertical: true }, () =>
|
||||
resultUsers.value?.map((user) =>
|
||||
h(NSpace, null, () => [
|
||||
h(NAvatar, { src: user.avatar + '@32w_32h', imgProps: { referrerpolicy: 'no-referrer' } }),
|
||||
h('span', user.name),
|
||||
]),
|
||||
),
|
||||
),
|
||||
meta: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
|
||||
onAfterLeave: () => {
|
||||
@@ -327,16 +339,25 @@ 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"> 前往 VTsuru.live 主站 </NButton>
|
||||
<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>
|
||||
<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>
|
||||
@@ -345,7 +366,9 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
<NCard size="small" embedded title="抽奖选项">
|
||||
<template #header-extra>
|
||||
<NButton size="small" secondary @click="lotteryOption = defaultOption" :disabled="isStartLottery"> 恢复默认 </NButton>
|
||||
<NButton size="small" secondary @click="lotteryOption = defaultOption" :disabled="isStartLottery">
|
||||
恢复默认
|
||||
</NButton>
|
||||
</template>
|
||||
<NSpace justify="center" align="center">
|
||||
<NTag :bordered="false"> 抽奖类型 </NTag>
|
||||
@@ -365,7 +388,13 @@ onUnmounted(() => {
|
||||
<NCollapseTransition>
|
||||
<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'">
|
||||
@@ -373,12 +402,21 @@ onUnmounted(() => {
|
||||
<template #trigger>
|
||||
<NInputGroup style="max-width: 250px">
|
||||
<NInputGroupLabel> 弹幕内容 </NInputGroupLabel>
|
||||
<NInput :disabled="isStartLottery" v-model:value="lotteryOption.danmakuKeyword" placeholder="留空则任何弹幕都可以" />
|
||||
<NInput
|
||||
:disabled="isStartLottery"
|
||||
v-model:value="lotteryOption.danmakuKeyword"
|
||||
placeholder="留空则任何弹幕都可以"
|
||||
/>
|
||||
</NInputGroup>
|
||||
</template>
|
||||
符合规则的弹幕才会被添加到抽奖队列中
|
||||
</NTooltip>
|
||||
<NRadioGroup v-model:value="lotteryOption.danmakuFilterType" name="判定类型" :disabled="isLottering" size="small">
|
||||
<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>
|
||||
@@ -387,7 +425,11 @@ onUnmounted(() => {
|
||||
<template v-else-if="lotteryOption.type == 'gift'">
|
||||
<NInputGroup style="max-width: 250px">
|
||||
<NInputGroupLabel> 最低价格 </NInputGroupLabel>
|
||||
<NInputNumber :disabled="isStartLottery" v-model:value="lotteryOption.giftMinPrice" placeholder="留空则不限制" />
|
||||
<NInputNumber
|
||||
:disabled="isStartLottery"
|
||||
v-model:value="lotteryOption.giftMinPrice"
|
||||
placeholder="留空则不限制"
|
||||
/>
|
||||
</NInputGroup>
|
||||
<NInputGroup style="max-width: 200px">
|
||||
<NInputGroupLabel> 礼物名称 </NInputGroupLabel>
|
||||
@@ -422,11 +464,20 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
<NCard v-if="originUsers" size="small">
|
||||
<NSpace justify="center" align="center">
|
||||
<NButton type="primary" @click="continueLottery" :loading="isStartLottery" :disabled="isStartLottery || isLotteried || !client"> 开始 </NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
@click="continueLottery"
|
||||
:loading="isStartLottery"
|
||||
:disabled="isStartLottery || isLotteried || !client"
|
||||
>
|
||||
开始
|
||||
</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> </NDivider>
|
||||
<NDivider style="margin: 20px 0 20px 0">
|
||||
<template v-if="isStartLottery"> 进行抽取前需要先停止 </template>
|
||||
</NDivider>
|
||||
<NSpace justify="center">
|
||||
<NButton
|
||||
type="primary"
|
||||
@@ -439,7 +490,9 @@ onUnmounted(() => {
|
||||
>
|
||||
进行抽取
|
||||
</NButton>
|
||||
<NButton type="info" secondary :disabled="isStartLottery || isLottering || !isLotteried" @click="reset"> 重置 </NButton>
|
||||
<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">
|
||||
@@ -447,7 +500,15 @@ onUnmounted(() => {
|
||||
<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)" />
|
||||
<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">
|
||||
@@ -462,7 +523,12 @@ onUnmounted(() => {
|
||||
{{ 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"
|
||||
@click="removeUser(item)"
|
||||
size="small"
|
||||
circle
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Delete24Filled" />
|
||||
</template>
|
||||
@@ -487,7 +553,9 @@ onUnmounted(() => {
|
||||
<NTime :time="item.time" />
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NButton type="error" size="small" @click="lotteryHistory.splice(lotteryHistory.indexOf(item), 1)"> 删除 </NButton>
|
||||
<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.uId">
|
||||
@@ -501,7 +569,14 @@ onUnmounted(() => {
|
||||
</NScrollbar>
|
||||
<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">
|
||||
<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">
|
||||
|
||||
@@ -14,9 +14,16 @@ import {
|
||||
Setting_Queue,
|
||||
} from '@/api/api-models'
|
||||
import { QueryGetAPI, QueryPostAPI, QueryPostAPIWithParams } from '@/api/query'
|
||||
import DanmakuClient, { DanmakuInfo, GiftInfo, RoomAuthInfo } from '@/data/DanmakuClient'
|
||||
import DanmakuClient, { RoomAuthInfo } from '@/data/DanmakuClient'
|
||||
import { QUEUE_API_URL } from '@/data/constants'
|
||||
import { Checkmark12Regular, ClipboardTextLtr24Filled, Delete24Filled, Dismiss16Filled, PeopleQueue24Filled, PresenceBlocked16Regular } from '@vicons/fluent'
|
||||
import {
|
||||
Checkmark12Regular,
|
||||
ClipboardTextLtr24Filled,
|
||||
Delete24Filled,
|
||||
Dismiss16Filled,
|
||||
PeopleQueue24Filled,
|
||||
PresenceBlocked16Regular,
|
||||
} from '@vicons/fluent'
|
||||
import { ReloadCircleSharp } from '@vicons/ionicons5'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { isSameDay } from 'date-fns'
|
||||
@@ -140,7 +147,10 @@ const queue = computed(() => {
|
||||
let list = new List(accountInfo ? originQueue.value : localQueues.value)
|
||||
.Where(
|
||||
(q) =>
|
||||
!filterName.value || (filterNameContains.value ? q?.user?.name.toLowerCase().includes(filterName.value.toLowerCase()) == true : q?.user?.name.toLowerCase() == filterName.value.toLowerCase()),
|
||||
!filterName.value ||
|
||||
(filterNameContains.value
|
||||
? q?.user?.name.toLowerCase().includes(filterName.value.toLowerCase()) == true
|
||||
: q?.user?.name.toLowerCase() == filterName.value.toLowerCase()),
|
||||
)
|
||||
.Where((q) => (q?.status ?? QueueStatus.Cancel) < QueueStatus.Finish)
|
||||
.OrderByDescending((q) => q.from == QueueFrom.Manual)
|
||||
@@ -342,7 +352,9 @@ function checkMessage(eventData: EventModel) {
|
||||
if (!settings.value.allowGift && !settings.value.allowIncreasePaymentBySendGift) {
|
||||
return false // { success: false, message: '不允许通过礼物排队' }
|
||||
}
|
||||
const nameNotMatch = (settings.value.giftNames?.length ?? 0) > 0 && settings.value.giftNames?.some((n) => eventData.msg.toLowerCase() === n.toLowerCase()) != true
|
||||
const nameNotMatch =
|
||||
(settings.value.giftNames?.length ?? 0) > 0 &&
|
||||
settings.value.giftNames?.some((n) => eventData.msg.toLowerCase() === n.toLowerCase()) != true
|
||||
const priceNotMatch = settings.value.minGiftPrice && eventData.price < settings.value.minGiftPrice
|
||||
if (settings.value.giftFilterType === QueueGiftFilterType.Or && (!nameNotMatch || !priceNotMatch)) {
|
||||
return true // { success: true, message: '' }
|
||||
@@ -371,7 +383,9 @@ async function onUpdateFunctionEnable() {
|
||||
if (accountInfo.value) {
|
||||
const oldValue = JSON.parse(JSON.stringify(accountInfo.value.settings.enableFunctions))
|
||||
if (accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.Queue)) {
|
||||
accountInfo.value.settings.enableFunctions = accountInfo.value.settings.enableFunctions.filter((f) => f != FunctionTypes.Queue)
|
||||
accountInfo.value.settings.enableFunctions = accountInfo.value.settings.enableFunctions.filter(
|
||||
(f) => f != FunctionTypes.Queue,
|
||||
)
|
||||
} else {
|
||||
accountInfo.value.settings.enableFunctions.push(FunctionTypes.Queue)
|
||||
}
|
||||
@@ -381,16 +395,22 @@ async function onUpdateFunctionEnable() {
|
||||
await SaveEnableFunctions(accountInfo.value?.settings.enableFunctions)
|
||||
.then((data) => {
|
||||
if (data.code == 200) {
|
||||
message.success(`已${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}队列功能`)
|
||||
message.success(
|
||||
`已${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}队列功能`,
|
||||
)
|
||||
} else {
|
||||
if (accountInfo.value) {
|
||||
accountInfo.value.settings.enableFunctions = oldValue
|
||||
}
|
||||
message.error(`队列功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${data.message}`)
|
||||
message.error(
|
||||
`队列功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${data.message}`,
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
message.error(`队列功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${err}`)
|
||||
message.error(
|
||||
`队列功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${err}`,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -544,7 +564,15 @@ const columns = [
|
||||
break
|
||||
}
|
||||
}
|
||||
return h(NTag, { type: statusType, size: 'small', style: data.status == QueueStatus.Progressing ? 'animation: animated-border 2.5s infinite;' : '' }, () => STATUS_MAP[data.status])
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: statusType,
|
||||
size: 'small',
|
||||
style: data.status == QueueStatus.Progressing ? 'animation: animated-border 2.5s infinite;' : '',
|
||||
},
|
||||
() => STATUS_MAP[data.status],
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -646,7 +674,9 @@ async function updateActive() {
|
||||
if (queueData.status != item.status) queueData.status = item.status
|
||||
if (queueData.giftPrice != item.giftPrice) {
|
||||
queueData.giftPrice = item.giftPrice
|
||||
message.info(`${queueData.user?.name} 通过发送礼物再次付费: ¥ ${(item?.giftPrice ?? 0) - (queueData?.giftPrice ?? 0)}, 当前总计付费: ¥ ${item.giftPrice}`)
|
||||
message.info(
|
||||
`${queueData.user?.name} 通过发送礼物再次付费: ¥ ${(item?.giftPrice ?? 0) - (queueData?.giftPrice ?? 0)}, 当前总计付费: ¥ ${item.giftPrice}`,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
originQueue.value.unshift(item)
|
||||
@@ -721,16 +751,25 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<NAlert type="info" v-if="accountInfo">
|
||||
启用队列功能
|
||||
<NSwitch :value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.Queue)" @update:value="onUpdateFunctionEnable" />
|
||||
<NSwitch
|
||||
:value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.Queue)"
|
||||
@update:value="onUpdateFunctionEnable"
|
||||
/>
|
||||
|
||||
<br />
|
||||
<NText depth="3">
|
||||
如果没有部署
|
||||
<NButton text type="primary" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank"> VtsuruEventFetcher </NButton>
|
||||
<NButton text type="primary" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank">
|
||||
VtsuruEventFetcher
|
||||
</NButton>
|
||||
则其需要保持此页面开启才能使用, 也不要同时开多个页面, 会导致重复 !(部署了则不影响)
|
||||
</NText>
|
||||
</NAlert>
|
||||
<NAlert type="warning" v-else title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑">
|
||||
<NAlert
|
||||
type="warning"
|
||||
v-else
|
||||
title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑"
|
||||
>
|
||||
<NButton tag="a" href="/manage" target="_blank" type="primary"> 前往登录或注册 </NButton>
|
||||
</NAlert>
|
||||
<br />
|
||||
@@ -746,7 +785,11 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
<br />
|
||||
<NCard>
|
||||
<NTabs v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.Queue)" animated display-directive="show:lazy">
|
||||
<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">
|
||||
@@ -760,7 +803,11 @@ onUnmounted(() => {
|
||||
<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" />
|
||||
@@ -772,19 +819,31 @@ onUnmounted(() => {
|
||||
</template>
|
||||
确定全部取消吗?
|
||||
</NPopconfirm>
|
||||
<NRadioGroup v-model:value="settings.sortType" :disabled="!configCanEdit" @update:value="updateSettings" type="button">
|
||||
<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>
|
||||
</NRadioGroup>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings"> 倒序 </NCheckbox>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings">
|
||||
倒序
|
||||
</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%;`">
|
||||
<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
|
||||
@@ -803,7 +862,12 @@ onUnmounted(() => {
|
||||
<template v-if="queueData.from == QueueFrom.Manual">
|
||||
<NTag size="small" :bordered="false"> 手动添加 </NTag>
|
||||
</template>
|
||||
<NSpace v-if="(queueData.from == QueueFrom.Danmaku || queueData.from == QueueFrom.Gift) && queueData.user?.fans_medal_wearing_status">
|
||||
<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">
|
||||
@@ -815,10 +879,17 @@ 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"> 付费 | {{ queueData.giftPrice }} </NTag>
|
||||
<NTag v-if="(queueData.giftPrice ?? 0) > 0" size="small" :bordered="false" type="error">
|
||||
付费 | {{ queueData.giftPrice }}
|
||||
</NTag>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText style="font-size: small">
|
||||
@@ -835,8 +906,15 @@ onUnmounted(() => {
|
||||
circle
|
||||
type="primary"
|
||||
style="height: 30px; width: 30px"
|
||||
:disabled="queue.findIndex((s) => s.id != queueData.id && s.status == QueueStatus.Progressing) > -1"
|
||||
@click="updateStatus(queueData, queueData.status == QueueStatus.Progressing ? QueueStatus.Waiting : QueueStatus.Progressing)"
|
||||
:disabled="
|
||||
queue.findIndex((s) => s.id != queueData.id && s.status == QueueStatus.Progressing) > -1
|
||||
"
|
||||
@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"
|
||||
@@ -856,7 +934,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>
|
||||
@@ -881,7 +965,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>
|
||||
@@ -937,7 +1027,12 @@ onUnmounted(() => {
|
||||
</template>
|
||||
<NInput v-else v-model:value="defaultKeyword" />
|
||||
</NInputGroup>
|
||||
<NRadioGroup v-model:value="settings.matchType" :disabled="!configCanEdit" @update:value="updateSettings" type="button">
|
||||
<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>
|
||||
@@ -949,21 +1044,60 @@ onUnmounted(() => {
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
</NInputGroup>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.enableOnStreaming" @update:checked="updateSettings" :disabled="!configCanEdit"> 仅在直播时才允许加入 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowAllDanmaku" @update:checked="updateSettings" :disabled="!configCanEdit"> 允许所有用户加入 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableOnStreaming"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
仅在直播时才允许加入
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowAllDanmaku"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
允许所有用户加入
|
||||
</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>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needJianzhang" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许舰长 </NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needTidu" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许提督 </NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needZongdu" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许总督 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needJianzhang"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许舰长
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needTidu"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许提督
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needZongdu"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许总督
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NSpace>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.allowGift" @update:checked="updateSettings" :disabled="!configCanEdit"> 允许通过发送礼物加入队列 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowGift"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
允许通过发送礼物加入队列
|
||||
</NCheckbox>
|
||||
<template v-if="settings.allowGift">
|
||||
<NInputGroup v-if="settings.allowGift" style="width: 250px">
|
||||
<NInputGroupLabel> 最低价格 </NInputGroupLabel>
|
||||
@@ -986,21 +1120,40 @@ onUnmounted(() => {
|
||||
/>
|
||||
</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>
|
||||
</template>
|
||||
<NCheckbox v-model:checked="settings.allowIncreasePaymentBySendGift" @update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowIncreasePaymentBySendGift"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
在队列中时允许继续发送礼物累计付费量 (仅限上方设定的礼物)
|
||||
</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"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
允许发送任意礼物来叠加付费量
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 冷却 (单位: 秒) </NDivider>
|
||||
<NCheckbox v-model:checked="settings.enableCooldown" @update:checked="updateSettings" :disabled="!configCanEdit"> 启用排队冷却 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableCooldown"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
启用排队冷却
|
||||
</NCheckbox>
|
||||
<NSpace v-if="settings.enableCooldown">
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 普通弹幕 </NInputGroupLabel>
|
||||
@@ -1024,9 +1177,27 @@ onUnmounted(() => {
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NDivider> OBS </NDivider>
|
||||
<NCheckbox v-model:checked="settings.showRequireInfo" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示底部的需求信息 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showPayment" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示付费信息 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showFanMadelInfo" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示用户粉丝牌 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showRequireInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示底部的需求信息
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showPayment"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示付费信息
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showFanMadelInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示用户粉丝牌
|
||||
</NCheckbox>
|
||||
<NDivider> 其他 </NDivider>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose"> 自动关闭加入队列失败时的提示消息 </NCheckbox>
|
||||
</NSpace>
|
||||
|
||||
@@ -241,9 +241,9 @@ function speakDirect(text: string) {
|
||||
return
|
||||
}
|
||||
synth.cancel()
|
||||
let u = new SpeechSynthesisUtterance()
|
||||
const u = new SpeechSynthesisUtterance()
|
||||
u.text = text
|
||||
let voices = synth.getVoices()
|
||||
const voices = synth.getVoices()
|
||||
const voice = voices.find((v) => v.name === settings.value.speechInfo.voice)
|
||||
if (voice) {
|
||||
u.voice = voice
|
||||
@@ -670,7 +670,7 @@ onUnmounted(() => {
|
||||
<NCollapseItem title="队列" name="1">
|
||||
<NEmpty v-if="speakQueue.length == 0"> 暂无 </NEmpty>
|
||||
<NList v-else size="small" bordered>
|
||||
<NListItem v-for="item in speakQueue">
|
||||
<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">
|
||||
|
||||
@@ -1,11 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { AddBiliBlackList, SaveEnableFunctions, useAccount } from '@/api/account'
|
||||
import { DanmakuUserInfo, EventDataTypes, EventModel, FunctionTypes, Setting_SongRequest, SongRequestFrom, SongRequestInfo, SongRequestStatus, SongsInfo } from '@/api/api-models'
|
||||
import {
|
||||
DanmakuUserInfo,
|
||||
EventDataTypes,
|
||||
EventModel,
|
||||
FunctionTypes,
|
||||
Setting_SongRequest,
|
||||
SongRequestFrom,
|
||||
SongRequestInfo,
|
||||
SongRequestStatus,
|
||||
SongsInfo,
|
||||
} from '@/api/api-models'
|
||||
import { QueryGetAPI, QueryPostAPI, QueryPostAPIWithParams } from '@/api/query'
|
||||
import SongPlayer from '@/components/SongPlayer.vue'
|
||||
import DanmakuClient, { DanmakuInfo, RoomAuthInfo, SCInfo } from '@/data/DanmakuClient'
|
||||
import DanmakuClient, { RoomAuthInfo } from '@/data/DanmakuClient'
|
||||
import { SONG_REQUEST_API_URL } from '@/data/constants'
|
||||
import { Checkmark12Regular, Delete24Filled, Dismiss16Filled, Info24Filled, Mic24Filled, PeopleQueue24Filled, Play24Filled, PresenceBlocked16Regular } from '@vicons/fluent'
|
||||
import {
|
||||
Checkmark12Regular,
|
||||
Delete24Filled,
|
||||
Dismiss16Filled,
|
||||
Info24Filled,
|
||||
Mic24Filled,
|
||||
PeopleQueue24Filled,
|
||||
Play24Filled,
|
||||
PresenceBlocked16Regular,
|
||||
} from '@vicons/fluent'
|
||||
import { ReloadCircleSharp } from '@vicons/ionicons5'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { isSameDay } from 'date-fns'
|
||||
@@ -190,7 +209,9 @@ async function getAllSong() {
|
||||
}
|
||||
}
|
||||
async function addSong(danmaku: EventModel) {
|
||||
console.log(`[OPEN-LIVE-Song-Request] 收到 [${danmaku.name}] 的点歌${danmaku.type == EventDataTypes.SC ? 'SC' : '弹幕'}: ${danmaku.msg}`)
|
||||
console.log(
|
||||
`[OPEN-LIVE-Song-Request] 收到 [${danmaku.name}] 的点歌${danmaku.type == EventDataTypes.SC ? 'SC' : '弹幕'}: ${danmaku.msg}`,
|
||||
)
|
||||
if (settings.value.enableOnStreaming && accountInfo.value?.streamerInfo?.isStreaming != true) {
|
||||
message.info('当前未在直播中, 无法添加点歌请求. 或者关闭设置中的仅允许直播时加入')
|
||||
return
|
||||
@@ -342,7 +363,9 @@ async function onUpdateFunctionEnable() {
|
||||
if (accountInfo.value) {
|
||||
const oldValue = JSON.parse(JSON.stringify(accountInfo.value.settings.enableFunctions))
|
||||
if (accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest)) {
|
||||
accountInfo.value.settings.enableFunctions = accountInfo.value.settings.enableFunctions.filter((f) => f != FunctionTypes.SongRequest)
|
||||
accountInfo.value.settings.enableFunctions = accountInfo.value.settings.enableFunctions.filter(
|
||||
(f) => f != FunctionTypes.SongRequest,
|
||||
)
|
||||
} else {
|
||||
accountInfo.value.settings.enableFunctions.push(FunctionTypes.SongRequest)
|
||||
}
|
||||
@@ -352,16 +375,22 @@ async function onUpdateFunctionEnable() {
|
||||
await SaveEnableFunctions(accountInfo.value?.settings.enableFunctions)
|
||||
.then((data) => {
|
||||
if (data.code == 200) {
|
||||
message.success(`已${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}点歌功能`)
|
||||
message.success(
|
||||
`已${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}点歌功能`,
|
||||
)
|
||||
} else {
|
||||
if (accountInfo.value) {
|
||||
accountInfo.value.settings.enableFunctions = oldValue
|
||||
}
|
||||
message.error(`点歌功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${data.message}`)
|
||||
message.error(
|
||||
`点歌功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${data.message}`,
|
||||
)
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
message.error(`点歌功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${err}`)
|
||||
message.error(
|
||||
`点歌功能${accountInfo.value?.settings.enableFunctions.includes(FunctionTypes.SongRequest) ? '启用' : '禁用'}失败: ${err}`,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -444,7 +473,14 @@ const columns = [
|
||||
NTooltip,
|
||||
{ trigger: 'hover' },
|
||||
{
|
||||
trigger: () => h(NTag, { bordered: false, size: 'small' }, data.from == SongRequestFrom.Manual ? () => h(NText, { italic: true }, () => '手动添加') : () => data.user?.name),
|
||||
trigger: () =>
|
||||
h(
|
||||
NTag,
|
||||
{ bordered: false, size: 'small' },
|
||||
data.from == SongRequestFrom.Manual
|
||||
? () => h(NText, { italic: true }, () => '手动添加')
|
||||
: () => data.user?.name,
|
||||
),
|
||||
default: () => (data.from == SongRequestFrom.Manual ? '就是主播自己' : data.user?.uid),
|
||||
},
|
||||
)
|
||||
@@ -518,7 +554,15 @@ const columns = [
|
||||
break
|
||||
}
|
||||
}
|
||||
return h(NTag, { type: statusType, size: 'small', style: data.status == SongRequestStatus.Singing ? 'animation: animated-border 2.5s infinite;' : '' }, () => STATUS_MAP[data.status])
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: statusType,
|
||||
size: 'small',
|
||||
style: data.status == SongRequestStatus.Singing ? 'animation: animated-border 2.5s infinite;' : '',
|
||||
},
|
||||
() => STATUS_MAP[data.status],
|
||||
)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -705,16 +749,25 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<NAlert type="info" v-if="accountInfo">
|
||||
启用点歌功能
|
||||
<NSwitch :value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.SongRequest)" @update:value="onUpdateFunctionEnable" />
|
||||
<NSwitch
|
||||
:value="accountInfo?.settings.enableFunctions.includes(FunctionTypes.SongRequest)"
|
||||
@update:value="onUpdateFunctionEnable"
|
||||
/>
|
||||
|
||||
<br />
|
||||
<NText depth="3">
|
||||
如果没有部署
|
||||
<NButton text type="primary" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank"> VtsuruEventFetcher </NButton>
|
||||
<NButton text type="primary" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank">
|
||||
VtsuruEventFetcher
|
||||
</NButton>
|
||||
则其需要保持此页面开启才能点歌, 也不要同时开多个页面, 会导致点歌重复 !(部署了则不影响)
|
||||
</NText>
|
||||
</NAlert>
|
||||
<NAlert type="warning" v-else title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑">
|
||||
<NAlert
|
||||
type="warning"
|
||||
v-else
|
||||
title="你尚未注册并登录 VTsuru.live, 大部分规则设置将不可用 (因为我懒得在前段重写一遍逻辑"
|
||||
>
|
||||
<NButton tag="a" href="/manage" target="_blank" type="primary"> 前往登录或注册 </NButton>
|
||||
</NAlert>
|
||||
<br />
|
||||
@@ -730,7 +783,11 @@ onUnmounted(() => {
|
||||
</NCard>
|
||||
<br />
|
||||
<NCard>
|
||||
<NTabs v-if="!accountInfo || accountInfo.settings.enableFunctions.includes(FunctionTypes.SongRequest)" animated display-directive="show:lazy">
|
||||
<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">
|
||||
@@ -744,13 +801,20 @@ onUnmounted(() => {
|
||||
<template #icon>
|
||||
<NIcon :component="Checkmark12Regular" />
|
||||
</template>
|
||||
今日已演唱 | {{ songs.filter((s) => s.status != SongRequestStatus.Cancel && isSameDay(s.finishAt ?? 0, Date.now())).length }} 首
|
||||
今日已演唱 |
|
||||
{{
|
||||
songs.filter((s) => s.status != SongRequestStatus.Cancel && isSameDay(s.finishAt ?? 0, Date.now()))
|
||||
.length
|
||||
}}
|
||||
首
|
||||
</NTag>
|
||||
<NInputGroup>
|
||||
<NInput placeholder="手动添加" v-model:value="newSongName" />
|
||||
<NButton type="primary" @click="addSongManual"> 添加 </NButton>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings"> 倒序 </NCheckbox>
|
||||
<NCheckbox v-if="configCanEdit" v-model:checked="settings.isReverse" @update:checked="updateSettings">
|
||||
倒序
|
||||
</NCheckbox>
|
||||
<NCheckbox v-else v-model:checked="isReverse"> 倒序 </NCheckbox>
|
||||
<NPopconfirm @positive-click="deactiveAllSongs">
|
||||
<template #trigger>
|
||||
@@ -769,10 +833,17 @@ onUnmounted(() => {
|
||||
</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%;`">
|
||||
<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>
|
||||
<div
|
||||
:style="`border-radius: 4px; background-color: ${song.status == SongRequestStatus.Singing ? '#75c37f' : '#577fb8'}; width: 10px; height: 20px`"
|
||||
></div>
|
||||
<NText strong style="font-size: 18px">
|
||||
{{ song.songName }}
|
||||
</NText>
|
||||
@@ -791,7 +862,12 @@ onUnmounted(() => {
|
||||
{{ song.user?.uid }}
|
||||
</NTooltip>
|
||||
</template>
|
||||
<NSpace v-if="(song.from == SongRequestFrom.Danmaku || song.from == SongRequestFrom.SC) && song.user?.fans_medal_wearing_status">
|
||||
<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">
|
||||
@@ -803,10 +879,21 @@ 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.scPrice ?? 0) }"> SC | {{ song.scPrice }} </NTag>
|
||||
<NTag
|
||||
v-if="song.from == SongRequestFrom.SC"
|
||||
size="small"
|
||||
:color="{ textColor: 'white', color: GetSCColor(song.scPrice ?? 0) }"
|
||||
>
|
||||
SC | {{ song.scPrice }}
|
||||
</NTag>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText style="font-size: small">
|
||||
@@ -819,7 +906,13 @@ onUnmounted(() => {
|
||||
<NSpace justify="end" align="center">
|
||||
<NTooltip v-if="song.song">
|
||||
<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>
|
||||
@@ -833,8 +926,17 @@ onUnmounted(() => {
|
||||
circle
|
||||
type="primary"
|
||||
style="height: 30px; width: 30px"
|
||||
:disabled="songs.findIndex((s) => s.id != song.id && s.status == SongRequestStatus.Singing) > -1"
|
||||
@click="updateSongStatus(song, song.status == SongRequestStatus.Singing ? SongRequestStatus.Waiting : SongRequestStatus.Singing)"
|
||||
:disabled="
|
||||
songs.findIndex((s) => s.id != song.id && s.status == SongRequestStatus.Singing) > -1
|
||||
"
|
||||
@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"
|
||||
@@ -854,7 +956,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>
|
||||
@@ -879,7 +987,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>
|
||||
@@ -949,24 +1063,71 @@ onUnmounted(() => {
|
||||
<NButton @click="updateSettings" type="info" :disabled="!configCanEdit">确定</NButton>
|
||||
</NInputGroup>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.enableOnStreaming" @update:checked="updateSettings" :disabled="!configCanEdit"> 仅在直播时才允许加入 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowAllDanmaku" @update:checked="updateSettings" :disabled="!configCanEdit"> 允许所有弹幕点歌 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableOnStreaming"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
仅在直播时才允许加入
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowAllDanmaku"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
允许所有弹幕点歌
|
||||
</NCheckbox>
|
||||
<template v-if="!settings.allowAllDanmaku">
|
||||
<NCheckbox v-model:checked="settings.needWearFanMedal" @update:checked="updateSettings" :disabled="!configCanEdit"> 需要拥有粉丝牌 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.needWearFanMedal"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
需要拥有粉丝牌
|
||||
</NCheckbox>
|
||||
<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>
|
||||
</NInputGroup>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needJianzhang" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许舰长 </NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needTidu" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许提督 </NCheckbox>
|
||||
<NCheckbox v-if="!settings.allowAllDanmaku" v-model:checked="settings.needZongdu" @update:checked="updateSettings" :disabled="!configCanEdit"> 只允许总督 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needJianzhang"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许舰长
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needTidu"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许提督
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-if="!settings.allowAllDanmaku"
|
||||
v-model:checked="settings.needZongdu"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
只允许总督
|
||||
</NCheckbox>
|
||||
</template>
|
||||
</NSpace>
|
||||
<NSpace align="center">
|
||||
<NCheckbox v-model:checked="settings.allowSC" @update:checked="updateSettings" :disabled="!configCanEdit"> 允许通过 SuperChat 点歌 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.allowSC" @update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
允许通过 SuperChat 点歌
|
||||
</NCheckbox>
|
||||
<span v-if="settings.allowSC">
|
||||
<NCheckbox v-model:checked="settings.allowSC" @update:checked="updateSettings" :disabled="!configCanEdit"> SC点歌无视限制 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowSC"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
SC点歌无视限制
|
||||
</NCheckbox>
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
@@ -981,15 +1142,31 @@ onUnmounted(() => {
|
||||
</NInputGroup>
|
||||
</NSpace>
|
||||
<NSpace>
|
||||
<NCheckbox v-model:checked="settings.onlyAllowSongList" @update:checked="updateSettings" :disabled="!configCanEdit">
|
||||
<NCheckbox
|
||||
v-model:checked="settings.onlyAllowSongList"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
仅允许点
|
||||
<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>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.allowFromWeb"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
允许通过网页点歌
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 冷却 (单位: 秒) </NDivider>
|
||||
<NCheckbox v-model:checked="settings.enableCooldown" @update:checked="updateSettings" :disabled="!configCanEdit"> 启用点歌冷却 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.enableCooldown"
|
||||
@update:checked="updateSettings"
|
||||
:disabled="!configCanEdit"
|
||||
>
|
||||
启用点歌冷却
|
||||
</NCheckbox>
|
||||
<NSpace v-if="settings.enableCooldown">
|
||||
<NInputGroup style="width: 250px">
|
||||
<NInputGroupLabel> 普通弹幕 </NInputGroupLabel>
|
||||
@@ -1014,9 +1191,27 @@ onUnmounted(() => {
|
||||
</NSpace>
|
||||
<NDivider> OBS </NDivider>
|
||||
<NSpace>
|
||||
<NCheckbox v-model:checked="settings.showRequireInfo" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示底部的需求信息 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showUserName" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示点歌用户名 </NCheckbox>
|
||||
<NCheckbox v-model:checked="settings.showFanMadelInfo" :disabled="!configCanEdit" @update:checked="updateSettings"> 显示点歌用户粉丝牌 </NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showRequireInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示底部的需求信息
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showUserName"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示点歌用户名
|
||||
</NCheckbox>
|
||||
<NCheckbox
|
||||
v-model:checked="settings.showFanMadelInfo"
|
||||
:disabled="!configCanEdit"
|
||||
@update:checked="updateSettings"
|
||||
>
|
||||
显示点歌用户粉丝牌
|
||||
</NCheckbox>
|
||||
</NSpace>
|
||||
<NDivider> 其他 </NDivider>
|
||||
<NCheckbox v-model:checked="isWarnMessageAutoClose"> 自动关闭点歌失败时的提示消息 </NCheckbox>
|
||||
|
||||
Reference in New Issue
Block a user