mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-07 02:46:55 +08:00
Compare commits
3 Commits
b97081a870
...
b24974540f
| Author | SHA1 | Date | |
|---|---|---|---|
| b24974540f | |||
| f267592e37 | |||
| dd29a141de |
@@ -452,21 +452,8 @@ function confirmTest() {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const stopWatch = watch(() => danmakuClient.state, (newState) => {
|
||||
if (newState === 'connected') {
|
||||
console.log('[ClientAutoAction] Danmaku client connected, initializing store...');
|
||||
autoActionStore.init();
|
||||
stopWatch();
|
||||
} else if (newState !== 'connecting' && newState !== 'waiting') {
|
||||
console.warn(`[ClientAutoAction] Danmaku client state is ${newState}, auto actions might not work.`);
|
||||
}
|
||||
}, { immediate: true });
|
||||
autoActionStore.init();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
console.log('[ClientAutoAction] Unmounted.');
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// 导入 Vue 和 Pinia 相关函数
|
||||
import { ref, computed, onUnmounted, watch } from 'vue';
|
||||
import { ref, computed, watch } from 'vue';
|
||||
import { defineStore, acceptHMRUpdate } from 'pinia';
|
||||
// 导入 API 模型和类型
|
||||
import { EventModel, GuardLevel, EventDataTypes } from '@/api/api-models.js';
|
||||
@@ -365,11 +365,15 @@ export const useAutoAction = defineStore('autoAction', () => {
|
||||
}
|
||||
|
||||
// --- 初始化与事件监听 ---
|
||||
|
||||
let isInited = false
|
||||
/**
|
||||
* 初始化自动操作系统
|
||||
*/
|
||||
function init() {
|
||||
if (isInited) {
|
||||
return;
|
||||
}
|
||||
isInited = true;
|
||||
// 计算属性,判断所有持久化数据是否加载完成
|
||||
const allLoaded = computed(() => isActionsLoaded.value && isIntervalLoaded.value && isModeLoaded.value && isIndexLoaded.value && isTriggersLoaded.value);
|
||||
|
||||
@@ -448,17 +452,6 @@ export const useAutoAction = defineStore('autoAction', () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 组件卸载时清理资源
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
console.log('[AutoAction] 清理定时器和监听器.');
|
||||
stopAllIndividualScheduledActions(); // 停止所有独立定时器
|
||||
stopGlobalTimer(); // 停止全局定时器
|
||||
clearInterval(tianXuanTimer); // 清除天选状态检查定时器
|
||||
});
|
||||
|
||||
// --- 操作项管理 (增删改查) ---
|
||||
|
||||
/**
|
||||
@@ -811,118 +804,71 @@ export const useAutoAction = defineStore('autoAction', () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建一个模拟事件用于测试
|
||||
let testEvent: EventModel;
|
||||
// 创建基础测试事件属性
|
||||
const baseTestEvent: Partial<EventModel> = {
|
||||
uid: testUid || 10000,
|
||||
uname: '测试用户',
|
||||
uface: '',
|
||||
open_id: 'test-open-id',
|
||||
ouid: 'test-ouid',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 0,
|
||||
guard_level: Math.floor(Math.random() * 3) + 1, // 1-3
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: Math.floor(Math.random() * 30) + 1 // 1-10
|
||||
};
|
||||
|
||||
// 根据不同触发类型创建不同的模拟事件
|
||||
let testEvent: EventModel;
|
||||
|
||||
switch (triggerType) {
|
||||
case TriggerType.DANMAKU:
|
||||
testEvent = {
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.Message,
|
||||
uid: 10000,
|
||||
uname: '测试用户',
|
||||
uface: '',
|
||||
open_id: 'test-open-id',
|
||||
ouid: 'test-ouid',
|
||||
msg: '测试弹幕消息',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 0,
|
||||
guard_level: 3,
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: 10
|
||||
};
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.GIFT:
|
||||
testEvent = {
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.Gift,
|
||||
uid: 10003,
|
||||
uname: '测试送礼者',
|
||||
uface: '',
|
||||
open_id: 'test-open-id-gift',
|
||||
ouid: 'test-ouid-gift',
|
||||
msg: '感谢 测试送礼者 赠送的 测试礼物 x 1',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
msg: '测试礼物',
|
||||
price: 100,
|
||||
guard_level: 1,
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: 15
|
||||
};
|
||||
num: 5
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.GUARD:
|
||||
const level = Math.floor(Math.random() * 3) + 1; // 1-3
|
||||
testEvent = {
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.Guard,
|
||||
uid: testUid || 10002,
|
||||
uname: '测试大航海成员',
|
||||
uface: '',
|
||||
open_id: 'test-open-id-guard',
|
||||
ouid: 'test-ouid-guard',
|
||||
msg: '测试大航海成员 开通了舰长',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 138,
|
||||
guard_level: Math.floor(Math.random() * 3) + 1, // 1-3
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: 20
|
||||
};
|
||||
msg: '舰长',
|
||||
price: level === 1 ? 19998 : level === 2 ? 1998 : 198,
|
||||
guard_level: level, // 1-3
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.FOLLOW:
|
||||
testEvent = {
|
||||
type: EventDataTypes.Message,
|
||||
uid: 10004,
|
||||
uname: '测试关注者',
|
||||
uface: '',
|
||||
open_id: 'test-open-id-follow',
|
||||
ouid: 'test-ouid-follow',
|
||||
msg: '测试关注者 关注了直播间',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 0,
|
||||
guard_level: 0,
|
||||
fans_medal_wearing_status: false,
|
||||
fans_medal_name: '',
|
||||
fans_medal_level: 0
|
||||
};
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.Follow,
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.ENTER:
|
||||
testEvent = {
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.Enter,
|
||||
uid: 10005,
|
||||
uname: '测试入场观众',
|
||||
uface: '',
|
||||
open_id: 'test-open-id-enter',
|
||||
ouid: 'test-ouid-enter',
|
||||
msg: '测试入场观众 进入了直播间',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 0,
|
||||
guard_level: 2,
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: 8
|
||||
};
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.SUPER_CHAT:
|
||||
testEvent = {
|
||||
...baseTestEvent,
|
||||
type: EventDataTypes.SC,
|
||||
uid: 10006,
|
||||
uname: '测试SC用户',
|
||||
uface: '',
|
||||
open_id: 'test-open-id-sc',
|
||||
ouid: 'test-ouid-sc',
|
||||
msg: '这是一条测试SC消息',
|
||||
time: Math.floor(Date.now() / 1000),
|
||||
num: 1,
|
||||
price: 30,
|
||||
guard_level: 0,
|
||||
fans_medal_wearing_status: true,
|
||||
fans_medal_name: '测试牌子',
|
||||
fans_medal_level: 25
|
||||
};
|
||||
price: Math.floor(Math.random() * 1000) + 10,
|
||||
} as EventModel;
|
||||
break;
|
||||
case TriggerType.SCHEDULED:
|
||||
// 对于定时任务,使用特殊的处理方式
|
||||
|
||||
@@ -3,20 +3,20 @@ import { updateNoteItemContentType, updateNotes } from '@/data/UpdateNote';
|
||||
import { NDivider, NGrid } from 'naive-ui';
|
||||
import { VNode } from 'vue';
|
||||
|
||||
const currentVer = '1'
|
||||
const savedVer = useStorage('UpdateNoteVer', 0)
|
||||
function renderContent(content: updateNoteItemContentType): VNode | string | undefined {
|
||||
if (Array.isArray(content)) {
|
||||
return h('div', { style: { whiteSpace: 'pre-wrap' } }, content.map(item => renderContent(item)))
|
||||
}
|
||||
if (typeof content === 'string') {
|
||||
return content
|
||||
}
|
||||
if (typeof content === 'function') {
|
||||
return content()
|
||||
}
|
||||
return undefined;
|
||||
function renderContent(content: updateNoteItemContentType): VNode | string | undefined {
|
||||
if (Array.isArray(content)) {
|
||||
return h('div', { style: { whiteSpace: 'pre-wrap' } }, content.map(item => renderContent(item)))
|
||||
}
|
||||
const getContent = (c: unknown) => {
|
||||
if (typeof c === 'string') {
|
||||
return c
|
||||
}
|
||||
if (typeof c === 'function') {
|
||||
return c()
|
||||
}
|
||||
}
|
||||
return h('span', { style: { whiteSpace: 'pre-wrap' } }, getContent(content))
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -32,9 +32,7 @@ import { VNode } from 'vue';
|
||||
<NDivider title-placement="left">
|
||||
{{ item.date }}
|
||||
</NDivider>
|
||||
<NGrid
|
||||
x-gap="10"
|
||||
>
|
||||
<NGrid x-gap="10">
|
||||
<template
|
||||
v-for="note in item.items"
|
||||
:key="note.title"
|
||||
|
||||
@@ -4,6 +4,30 @@ import { VNode } from "vue";
|
||||
import { FETCH_API } from "./constants";
|
||||
|
||||
export const updateNotes: updateNoteType[] = [
|
||||
{
|
||||
ver: 4,
|
||||
date: '2025.4.22',
|
||||
items: [
|
||||
{
|
||||
type: 'new',
|
||||
title: '添加自动操作功能',
|
||||
content: [
|
||||
[
|
||||
'EventFetcher客户端新增多种自动操作类型支持,包括弹幕自动回复、礼物感谢、上舰发送私信、关注感谢、入场欢迎、定时发送和SC感谢等, 可以执行js代码',
|
||||
() => h(NImage, { src: 'https://pan.suki.club/d/vtsuru/imgur/QQ20250422-221703.png', width: 300 }),
|
||||
],
|
||||
[
|
||||
'使用模板系统,支持随机回复、自定义表达式和条件判断等\r\n',
|
||||
'数据持久化存储,各类操作配置和运行状态不会丢失\r\n\r\n',
|
||||
'发送弹幕和私信需要客户端扫码登录, 客户端安装方式:',
|
||||
() => h(NButton, {
|
||||
text: true, tag: 'a', href: 'https://www.wolai.com/carN6qvUm3FErze9Xo53ii', target: '_blank', type: 'info'
|
||||
}, () => '查看介绍'),
|
||||
]
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
ver: 3,
|
||||
date: '2025.4.15',
|
||||
|
||||
@@ -8,11 +8,13 @@ import {
|
||||
MoreHorizontal24Filled,
|
||||
TabletSpeaker24Filled,
|
||||
VehicleShip24Filled,
|
||||
VideoAdd20Filled
|
||||
VideoAdd20Filled,
|
||||
Chat24Filled,
|
||||
PersonFeedback24Filled
|
||||
} from '@vicons/fluent'
|
||||
import { AnalyticsSharp, Calendar, Chatbox, ListCircle, MusicalNote } from '@vicons/ionicons5'
|
||||
import { useWindowSize } from '@vueuse/core'
|
||||
import { NButton, NDivider, NEllipsis, NFlex, NGradientText, NGrid, NGridItem, NIcon, NNumberAnimation, NSpace, NText, NTooltip } from 'naive-ui'
|
||||
import { NButton, NDivider, NEllipsis, NFlex, NGradientText, NGrid, NGridItem, NIcon, NNumberAnimation, NSpace, NText, NTooltip, NAlert, NCard, NStatistic, NTag, NBadge } from 'naive-ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import vtb from '@/svgs/ic_vtuber.svg'
|
||||
|
||||
@@ -29,6 +31,11 @@ const functions = [
|
||||
desc: '通过上舰, Superchat, 赠送礼物等操作可以获取积分, 并通过积分兑换虚拟或者实体礼物',
|
||||
icon: BookCoins20Filled,
|
||||
},
|
||||
{
|
||||
name: '弹幕机 (OBS',
|
||||
desc: '在OBS上显示直播间弹幕、礼物和互动内容,兼容blivechat样式 (开发中',
|
||||
icon: Chat24Filled,
|
||||
},
|
||||
{
|
||||
name: '日程表',
|
||||
desc: '提供多种样式的日程表',
|
||||
@@ -117,200 +124,350 @@ onMounted(async () => {
|
||||
vertical
|
||||
justify="center"
|
||||
align="center"
|
||||
style="padding-top: 30px"
|
||||
style="padding-top: 30px; padding-bottom: 30px;"
|
||||
>
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
:size="width > 700 ? 50 : 0"
|
||||
>
|
||||
<vtb />
|
||||
<!-- 顶部标题部分 -->
|
||||
<NCard style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: none; width: 90vw; max-width: 1400px; ">
|
||||
<NSpace
|
||||
vertical
|
||||
justify="center"
|
||||
align="center"
|
||||
:size="width > 700 ? 50 : 0"
|
||||
>
|
||||
<NGradientText
|
||||
size="3rem"
|
||||
:gradient="{
|
||||
deg: 180,
|
||||
from: '#e5e5e5',
|
||||
to: '#c2ebeb',
|
||||
}"
|
||||
style="font-weight: 700"
|
||||
>
|
||||
VTSURU.LIVE
|
||||
</NGradientText>
|
||||
<NText style="font-size: 1.5em; font-weight: 500; color: white">
|
||||
一个给主播提供便利功能的网站 😊
|
||||
</NText>
|
||||
<span />
|
||||
<vtb />
|
||||
<NSpace
|
||||
vertical
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<NSpace
|
||||
vertical
|
||||
justify="end"
|
||||
<NGradientText
|
||||
size="3rem"
|
||||
:gradient="{
|
||||
deg: 180,
|
||||
from: '#e5e5e5',
|
||||
to: '#c2ebeb',
|
||||
}"
|
||||
style="font-weight: 700"
|
||||
>
|
||||
VTSURU.LIVE
|
||||
</NGradientText>
|
||||
<NText style="font-size: 1.5em; font-weight: 500; color: white">
|
||||
一个给主播提供便利功能的网站 😊
|
||||
</NText>
|
||||
<span />
|
||||
<NSpace
|
||||
justify="center"
|
||||
align="center"
|
||||
>
|
||||
<NSpace align="center">
|
||||
<NSpace
|
||||
vertical
|
||||
justify="end"
|
||||
>
|
||||
<NText
|
||||
style="font-size: medium"
|
||||
italic
|
||||
>
|
||||
我是主播
|
||||
</NText>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$router.push({ name: 'manage-index' })"
|
||||
>
|
||||
开始使用
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NSpace vertical>
|
||||
<NText
|
||||
style="font-size: medium"
|
||||
italic
|
||||
>
|
||||
我是观众
|
||||
</NText>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
secondary
|
||||
bordered
|
||||
@click="$router.push({ name: 'bili-user' })"
|
||||
>
|
||||
用户主页
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
<NButton
|
||||
size="large"
|
||||
@click="$router.push('/@Megghy')"
|
||||
>
|
||||
<NText
|
||||
style="font-size: medium"
|
||||
italic
|
||||
>
|
||||
我是主播
|
||||
</NText>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
@click="$router.push({ name: 'manage-index' })"
|
||||
>
|
||||
开始使用
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NSpace vertical>
|
||||
<NText
|
||||
style="font-size: medium"
|
||||
italic
|
||||
>
|
||||
我是观众
|
||||
</NText>
|
||||
<NButton
|
||||
type="primary"
|
||||
size="small"
|
||||
secondary
|
||||
bordered
|
||||
@click="$router.push({ name: 'bili-user' })"
|
||||
>
|
||||
用户主页
|
||||
</NButton>
|
||||
</NSpace>
|
||||
展示
|
||||
</NButton>
|
||||
<NButton
|
||||
size="large"
|
||||
tag="a"
|
||||
href="https://play-live.bilibili.com/details/1698742711771"
|
||||
target="_blank"
|
||||
color="#ff778f"
|
||||
>
|
||||
幻星平台
|
||||
</NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
size="large"
|
||||
@click="$router.push({ name: 'about' })"
|
||||
>
|
||||
关于
|
||||
</NButton>
|
||||
</NSpace>
|
||||
<NButton
|
||||
size="large"
|
||||
@click="$router.push('/@Megghy')"
|
||||
>
|
||||
展示
|
||||
</NButton>
|
||||
<NButton
|
||||
size="large"
|
||||
tag="a"
|
||||
href="https://play-live.bilibili.com/details/1698742711771"
|
||||
target="_blank"
|
||||
color="#ff778f"
|
||||
>
|
||||
幻星平台
|
||||
</NButton>
|
||||
<NButton
|
||||
type="info"
|
||||
size="large"
|
||||
@click="$router.push({ name: 'about' })"
|
||||
>
|
||||
关于
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
|
||||
<NDivider style="width: 90vw">
|
||||
<NText :depth="3">
|
||||
本站用户
|
||||
</NText>
|
||||
<NDivider vertical />
|
||||
<NNumberAnimation
|
||||
:from="0"
|
||||
:to="indexData?.userCount"
|
||||
show-separator
|
||||
/>
|
||||
</NDivider>
|
||||
<NGrid
|
||||
cols="1 s:2 m:3 l:4 xl:5 2xl:5"
|
||||
x-gap="50"
|
||||
y-gap="50"
|
||||
style="max-width: 80vw"
|
||||
responsive="screen"
|
||||
>
|
||||
<NGridItem
|
||||
v-for="item in functions"
|
||||
:key="item.name"
|
||||
>
|
||||
<NSpace
|
||||
align="end"
|
||||
:wrap="false"
|
||||
>
|
||||
<NIcon
|
||||
:component="item.icon"
|
||||
:color="iconColor"
|
||||
size="20"
|
||||
/>
|
||||
<NEllipsis>
|
||||
<NText class="index-feature header">
|
||||
{{ item.name }}
|
||||
</NText>
|
||||
</NEllipsis>
|
||||
</NSpace>
|
||||
<NText class="index-feature content">
|
||||
{{ item.desc }}
|
||||
</NText>
|
||||
</NGridItem>
|
||||
</NGrid>
|
||||
<NDivider style="width: 90vw">
|
||||
正在使用本站的主播们
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
随机展示不分先后, 仅粉丝数大于500的主播
|
||||
</NTooltip>
|
||||
</NDivider>
|
||||
<NFlex
|
||||
v-if="indexData"
|
||||
vertical
|
||||
style="max-width: 80vw;"
|
||||
<!-- 用户统计部分 -->
|
||||
<NCard
|
||||
style="background: rgba(255, 255, 255, 0.05); backdrop-filter: blur(10px);
|
||||
border: none; width: 90vw; max-width: 1400px;"
|
||||
size="small"
|
||||
>
|
||||
<NFlex
|
||||
align="center"
|
||||
justify="center"
|
||||
:size="32"
|
||||
align="center"
|
||||
>
|
||||
<NText style="font-size: 0.9rem; color: rgba(255,255,255,0.7);">
|
||||
本站用户: <NNumberAnimation
|
||||
:from="0"
|
||||
:to="indexData?.userCount"
|
||||
show-separator
|
||||
/>
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
|
||||
<!-- 功能列表部分 -->
|
||||
<NCard style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: none; width: 90vw; max-width: 1400px; margin-bottom: 20px;">
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
v-for="streamer in indexData?.streamers"
|
||||
:key="streamer.name"
|
||||
style="display: flex;"
|
||||
align="center"
|
||||
justify="center"
|
||||
align="center"
|
||||
style="margin-bottom: 20px;"
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
:src="streamer.avatar + '@64w'"
|
||||
referrerpolicy="no-referrer"
|
||||
height="32"
|
||||
style="border-radius: 50%;"
|
||||
>
|
||||
</div>
|
||||
<NButton
|
||||
tag="a"
|
||||
:href="'@' + streamer.name"
|
||||
text
|
||||
<NText style="font-size: 1.2rem; font-weight: 500; background-image: linear-gradient(to right, #e5e5e5, #c2ebeb); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
|
||||
网站功能
|
||||
</NText>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
:wrap="true"
|
||||
justify="center"
|
||||
style="gap: 15px;"
|
||||
>
|
||||
<NCard
|
||||
v-for="item in functions"
|
||||
:key="item.name"
|
||||
style="width: 300px; max-width: 100%; background: rgba(255, 255, 255, 0.2); border: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);"
|
||||
hoverable
|
||||
>
|
||||
{{ streamer.uname || streamer.name }}
|
||||
</NButton>
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
align="center"
|
||||
style="margin-bottom: 10px;"
|
||||
>
|
||||
<NIcon
|
||||
:component="item.icon"
|
||||
size="24"
|
||||
color="white"
|
||||
/>
|
||||
<NText style="font-size: 1.1rem; font-weight: 500; margin-left: 10px; color: white;">
|
||||
{{ item.name }}
|
||||
</NText>
|
||||
</NFlex>
|
||||
<NText style="line-height: 1.6; color: rgba(255, 255, 255, 0.9);">
|
||||
{{ item.desc }}
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
<NText>
|
||||
还有更多...
|
||||
</NText>
|
||||
<NText depth="3">
|
||||
如果你不想要被展示在主页, 请前往
|
||||
<NButton
|
||||
text
|
||||
@click="$router.push({ name: 'manage-index', query: { tab: 'setting', setting: 'index' } })"
|
||||
</NCard>
|
||||
|
||||
<!-- 客户端专属功能部分 -->
|
||||
<NCard style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: none; width: 90vw; max-width: 1400px; margin-bottom: 20px;">
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
justify="center"
|
||||
align="center"
|
||||
style="margin-bottom: 20px;"
|
||||
>
|
||||
这里
|
||||
</NButton>
|
||||
进行设置
|
||||
</NText>
|
||||
</NFlex>
|
||||
<NDivider style="width: 90vw" />
|
||||
<NText style="font-size: 1.2rem; font-weight: 500; background-image: linear-gradient(to right, #e5e5e5, #c2ebeb); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
|
||||
客户端功能
|
||||
</NText>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
:wrap="true"
|
||||
justify="center"
|
||||
style="gap: 20px;"
|
||||
>
|
||||
<NCard
|
||||
style="width: 380px; max-width: 100%; background: rgba(255, 255, 255, 0.2); border: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);"
|
||||
hoverable
|
||||
>
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
align="center"
|
||||
style="margin-bottom: 10px;"
|
||||
>
|
||||
<NIcon
|
||||
:component="PersonFeedback24Filled"
|
||||
size="24"
|
||||
color="white"
|
||||
/>
|
||||
<NText style="font-size: 1.1rem; font-weight: 500; margin-left: 10px; color: white;">
|
||||
自动操作
|
||||
</NText>
|
||||
</NFlex>
|
||||
<NText style="line-height: 1.6; color: rgba(255, 255, 255, 0.9);">
|
||||
支持弹幕自动回复、礼物感谢、上舰私信、关注感谢、入场欢迎、定时发送和SC感谢等功能,使用模板系统和JS执行环境,可定制化程度挺高
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
|
||||
<NCard
|
||||
style="width: 380px; max-width: 100%; background: rgba(255, 255, 255, 0.2); border: none; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);"
|
||||
hoverable
|
||||
>
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
align="center"
|
||||
style="margin-bottom: 10px;"
|
||||
>
|
||||
<NIcon
|
||||
:component="Chat24Filled"
|
||||
size="24"
|
||||
color="white"
|
||||
/>
|
||||
<NText style="font-size: 1.1rem; font-weight: 500; margin-left: 10px; color: white;">
|
||||
弹幕机 (客户端)
|
||||
</NText>
|
||||
</NFlex>
|
||||
<NText style="line-height: 1.6; color: rgba(255, 255, 255, 0.9);">
|
||||
在自己电脑上显示直播间弹幕、礼物和互动内容
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
justify="center"
|
||||
style="margin-top: 20px;"
|
||||
>
|
||||
<NSpace>
|
||||
<NButton
|
||||
type="primary"
|
||||
tag="a"
|
||||
href="https://www.wolai.com/carN6qvUm3FErze9Xo53ii"
|
||||
target="_blank"
|
||||
>
|
||||
<template #icon>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
客户端安装说明
|
||||
</NButton>
|
||||
<NButton
|
||||
ghost
|
||||
tag="a"
|
||||
href="https://github.com/Megghy/vtsuru-fetvher-client"
|
||||
target="_blank"
|
||||
color="white"
|
||||
>
|
||||
客户端代码
|
||||
</NButton>
|
||||
<NButton
|
||||
ghost
|
||||
tag="a"
|
||||
href="https://github.com/Megghy/vtsuru.live/tree/master/src/client"
|
||||
target="_blank"
|
||||
color="white"
|
||||
>
|
||||
逻辑代码
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
|
||||
<!-- 使用本站的主播部分 -->
|
||||
<NCard style="background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border: none; width: 90vw; max-width: 1400px; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);">
|
||||
<NFlex vertical>
|
||||
<NFlex
|
||||
justify="center"
|
||||
align="center"
|
||||
style="margin-bottom: 20px;"
|
||||
>
|
||||
<NText style="font-size: 1.2rem; font-weight: 500; background-image: linear-gradient(to right, #e5e5e5, #c2ebeb); -webkit-background-clip: text; -webkit-text-fill-color: transparent;">
|
||||
正在使用本站的主播们
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
随机展示不分先后, 仅粉丝数大于500的主播
|
||||
</NTooltip>
|
||||
</NText>
|
||||
</NFlex>
|
||||
|
||||
<NFlex
|
||||
v-if="indexData"
|
||||
vertical
|
||||
style="max-width: 90vw;"
|
||||
>
|
||||
<NFlex
|
||||
align="center"
|
||||
justify="center"
|
||||
:size="32"
|
||||
:wrap="true"
|
||||
style="gap: 10px;"
|
||||
>
|
||||
<NFlex
|
||||
v-for="streamer in indexData?.streamers"
|
||||
:key="streamer.name"
|
||||
style="display: flex;"
|
||||
align="center"
|
||||
justify="center"
|
||||
>
|
||||
<div>
|
||||
<img
|
||||
:src="streamer.avatar + '@64w'"
|
||||
referrerpolicy="no-referrer"
|
||||
height="32"
|
||||
style="border-radius: 50%;"
|
||||
>
|
||||
</div>
|
||||
<NButton
|
||||
tag="a"
|
||||
:href="'@' + streamer.name"
|
||||
text
|
||||
>
|
||||
{{ streamer.uname || streamer.name }}
|
||||
</NButton>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
<NText style="text-align: center; margin-top: 10px; color: white;">
|
||||
还有更多...
|
||||
</NText>
|
||||
<NText
|
||||
depth="3"
|
||||
style="text-align: center; margin-top: 5px;"
|
||||
>
|
||||
如果你不想要被展示在主页, 请前往
|
||||
<NButton
|
||||
text
|
||||
@click="$router.push({ name: 'manage-index', query: { tab: 'setting', setting: 'index' } })"
|
||||
>
|
||||
这里
|
||||
</NButton>
|
||||
进行设置
|
||||
</NText>
|
||||
</NFlex>
|
||||
</NFlex>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
<NSpace
|
||||
style="position: absolute; bottom: 0; margin: 0 auto; width: 100vw"
|
||||
@@ -333,22 +490,11 @@ onMounted(async () => {
|
||||
</template>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
body
|
||||
margin:0
|
||||
.index-background
|
||||
display: abslute;
|
||||
height: 100vh;
|
||||
background: #8360c3; /* fallback for old browsers */
|
||||
background: -webkit-linear-gradient(to right, #2ebf91, #8360c3); /* Chrome 10-25, Safari 5.1-6 */
|
||||
background: linear-gradient(to right, #2ebf91, #8360c3); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
|
||||
overflow: auto
|
||||
|
||||
.index-background .header
|
||||
font-size: 1.3rem;
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
.index-background .content
|
||||
max-width: 300px;
|
||||
font-size: 17px;
|
||||
color: white;
|
||||
padding-bottom: 50px;
|
||||
</style>
|
||||
|
||||
@@ -278,10 +278,13 @@ async function ChangeBili() {
|
||||
isLoading.value = false
|
||||
})
|
||||
}
|
||||
onMounted(() => {
|
||||
|
||||
checkUpdateNote();
|
||||
})
|
||||
onUnmounted(() => {
|
||||
turnstile.value?.remove()
|
||||
// 当进入管理页时检查更新日志
|
||||
checkUpdateNote();
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
@@ -361,7 +361,8 @@ function GetPlayButton(song: SongsInfo) {
|
||||
// --- New: Helper function for Song Request Options ---
|
||||
function getOptionDisplay(options?: SongRequestOption) {
|
||||
if (!options) {
|
||||
return h('span', '无特殊要求');
|
||||
// 为"无特殊要求"添加 'empty-placeholder' 类
|
||||
return h('span', { class: 'empty-placeholder' }, '无特殊要求');
|
||||
}
|
||||
|
||||
const conditions: VNode[] = [];
|
||||
@@ -383,7 +384,8 @@ function getOptionDisplay(options?: SongRequestOption) {
|
||||
}
|
||||
|
||||
if (conditions.length === 0) {
|
||||
return h('span', '无特殊要求');
|
||||
// 为"无特殊要求"添加 'empty-placeholder' 类
|
||||
return h('span', { class: 'empty-placeholder' }, '无特殊要求');
|
||||
}
|
||||
|
||||
// Use NFlex for better wrapping
|
||||
@@ -902,7 +904,11 @@ export const Config = defineTemplateConfig([
|
||||
>
|
||||
{{ tag }}
|
||||
</n-tag>
|
||||
<span v-if="!song.tags || song.tags.length === 0">无标签</span>
|
||||
<!-- 为"无标签"添加 'empty-placeholder' 类 -->
|
||||
<span
|
||||
v-if="!song.tags || song.tags.length === 0"
|
||||
class="empty-placeholder"
|
||||
>无标签</span>
|
||||
</n-flex>
|
||||
</td>
|
||||
<td>
|
||||
@@ -1432,4 +1438,15 @@ html.dark .language-link.selected-language {
|
||||
color: currentColor !important; fill: currentColor !important;
|
||||
}
|
||||
|
||||
/* --- NEW: Style for empty placeholders --- */
|
||||
.empty-placeholder {
|
||||
color: #999999; /* Use a standard gray color */
|
||||
font-style: italic; /* Optional: make it italic */
|
||||
font-size: 0.9em; /* Optional: slightly smaller */
|
||||
}
|
||||
|
||||
html.dark .empty-placeholder {
|
||||
color: var(--text-color-3); /* Use theme variable for dark mode */
|
||||
}
|
||||
|
||||
</style>
|
||||
Reference in New Issue
Block a user