mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
add livelottery obs compoent
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
"vue-router": "4",
|
||||
"vue-turnstile": "^1.0.0",
|
||||
"vue3-aplayer": "^1.7.3",
|
||||
"vue3-marquee": "^4.1.0",
|
||||
"vuex": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
30
src/App.vue
30
src/App.vue
@@ -2,18 +2,21 @@
|
||||
<NMessageProvider>
|
||||
<NNotificationProvider>
|
||||
<NConfigProvider :theme-overrides="themeOverrides" :theme="theme" style="height: 100vh" :locale="zhCN" :date-locale="dateZhCN">
|
||||
<NElement style="height: 100vh">
|
||||
<Suspense>
|
||||
<ViewerLayout v-if="layout == 'viewer'" />
|
||||
<ManageLayout v-else-if="layout == 'manage'" />
|
||||
<template v-else>
|
||||
<RouterView />
|
||||
</template>
|
||||
<template #fallback>
|
||||
<NSpin size="large" show/>
|
||||
</template>
|
||||
</Suspense>
|
||||
</NElement>
|
||||
<Suspense>
|
||||
<div style="height: 100vh">
|
||||
<NElement style="height: 100%;" v-if="layout != 'obs'">
|
||||
<ViewerLayout v-if="layout == 'viewer'" />
|
||||
<ManageLayout v-else-if="layout == 'manage'" />
|
||||
<template v-else-if="layout == ''">
|
||||
<RouterView />
|
||||
</template>
|
||||
</NElement>
|
||||
<RouterView v-else/>
|
||||
</div>
|
||||
<template #fallback>
|
||||
<NSpin size="large" show />
|
||||
</template>
|
||||
</Suspense>
|
||||
</NConfigProvider>
|
||||
</NNotificationProvider>
|
||||
</NMessageProvider>
|
||||
@@ -38,6 +41,9 @@ const layout = computed(() => {
|
||||
} else if (route.path.startsWith('/manage')) {
|
||||
document.title = route.meta.title + ' · 管理 · VTsuru'
|
||||
return 'manage'
|
||||
} else if (route.path.startsWith('/obs')) {
|
||||
document.title = route.meta.title + ' · OBS · VTsuru'
|
||||
return 'obs'
|
||||
} else {
|
||||
document.title = route.meta.title + ' · VTsuru'
|
||||
return ''
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface AccountInfo extends UserInfo {
|
||||
settings: UserSetting
|
||||
token: string
|
||||
|
||||
biliAuthCode?: string
|
||||
biliAuthCodeStatus: BiliAuthCodeStatusType
|
||||
|
||||
eventFetcherOnline: boolean
|
||||
@@ -236,3 +237,22 @@ export interface OpenLiveInfo {
|
||||
websocket_info: WebsocketInfo
|
||||
anchor_info: AnchorInfo
|
||||
}
|
||||
export interface OpenLiveLotteryUserInfo {
|
||||
name: string
|
||||
uId: number
|
||||
level?: number
|
||||
avatar: string
|
||||
fans_medal_level: number
|
||||
fans_medal_name: string //粉丝勋章名
|
||||
fans_medal_wearing_status: boolean //该房间粉丝勋章佩戴情况
|
||||
guard_level: number
|
||||
}
|
||||
export enum OpenLiveLotteryType{
|
||||
Waiting,
|
||||
Result
|
||||
}
|
||||
export interface UpdateLiveLotteryUsersModel {
|
||||
users: OpenLiveLotteryUserInfo[]
|
||||
resultUsers: OpenLiveLotteryUserInfo[]
|
||||
type: OpenLiveLotteryType
|
||||
}
|
||||
@@ -205,6 +205,20 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/obs',
|
||||
name: 'obs',
|
||||
children: [
|
||||
{
|
||||
path: 'live-lottery',
|
||||
name: 'obs-live-lottery',
|
||||
component: () => import('@/views/obs/LiveLotteryOBS.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'notfound',
|
||||
|
||||
7
src/views/manage/MusicRequestManage.vue
Normal file
7
src/views/manage/MusicRequestManage.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
1
|
||||
</template>
|
||||
168
src/views/obs/LiveLotteryOBS.vue
Normal file
168
src/views/obs/LiveLotteryOBS.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<script setup lang="ts">
|
||||
import { OpenLiveLotteryType, OpenLiveLotteryUserInfo, UpdateLiveLotteryUsersModel } from '@/api/api-models'
|
||||
import { QueryGetAPI } from '@/api/query'
|
||||
import { LOTTERY_API_URL } from '@/data/constants'
|
||||
import { useElementSize } from '@vueuse/core'
|
||||
import { NCard, NDivider, NEmpty, NSpace, NText, useMessage } from 'naive-ui'
|
||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { Vue3Marquee } from 'vue3-marquee'
|
||||
|
||||
const props = defineProps<{
|
||||
code?: string
|
||||
}>()
|
||||
|
||||
const message = useMessage()
|
||||
const route = useRoute()
|
||||
const currentCode = computed(() => {
|
||||
return props.code ?? route.query.code
|
||||
})
|
||||
const listContainerRef = ref()
|
||||
const { height, width } = useElementSize(listContainerRef)
|
||||
|
||||
const result = ref(await getUsers())
|
||||
const users = computed(() => {
|
||||
return result.value?.users
|
||||
})
|
||||
const isMoreThanContainer = computed(() => {
|
||||
return (users.value?.length ?? 0) * 50 > height.value
|
||||
})
|
||||
|
||||
async function getUsers() {
|
||||
try {
|
||||
const data = await QueryGetAPI<UpdateLiveLotteryUsersModel>(LOTTERY_API_URL + 'live/get-users', {
|
||||
code: currentCode.value,
|
||||
})
|
||||
if (data.code == 200) {
|
||||
console.log('[OPEN-LIVE] 已获历史抽奖用户')
|
||||
return data.data
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
return {
|
||||
users: [],
|
||||
resultUsers: [],
|
||||
type: OpenLiveLotteryType.Waiting,
|
||||
} as UpdateLiveLotteryUsersModel
|
||||
}
|
||||
|
||||
let timer: any
|
||||
onMounted(() => {
|
||||
timer = setInterval(async () => {
|
||||
const r = await getUsers()
|
||||
if (r) {
|
||||
result.value = r
|
||||
}
|
||||
}, 2000)
|
||||
})
|
||||
onUnmounted(() => {
|
||||
clearInterval(timer)
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="lottery-background" v-bind="$attrs">
|
||||
<p class="lottery-header">抽奖</p>
|
||||
<NDivider v-if="result.type == OpenLiveLotteryType.Waiting" class="lottery-divider">
|
||||
<p class="lottery-header-count">已有 {{ users?.length ?? 0 }} 人</p>
|
||||
</NDivider>
|
||||
<div class="lottery-content" ref="listContainerRef">
|
||||
<template v-if="users.length > 0">
|
||||
<Vue3Marquee v-if="result.type == OpenLiveLotteryType.Waiting" vertical :pause="!isMoreThanContainer" :duration="20" :style="`height: ${height}px;`">
|
||||
<span class="lottery-list-item" :id="index.toString()" v-for="(user, index) in users" :key="user.uId" style="height: 50px">
|
||||
<img class="lottery-avatar" :src="user.avatar + '@30h'" referrerpolicy="no-referrer" />
|
||||
<div>
|
||||
<p class="lottery-name">{{ user.name }}</p>
|
||||
</div>
|
||||
</span>
|
||||
</Vue3Marquee>
|
||||
</template>
|
||||
<div v-else style="position: relative; top: 20%">
|
||||
<NEmpty description="暂无人参与" />
|
||||
</div>
|
||||
<template v-if="result.type == OpenLiveLotteryType.Result">
|
||||
<p style="text-align: center; font-size: 20px; margin: 0; font-weight: bold; color: #eeabab">结果</p>
|
||||
<Vue3Marquee v-if="100 * result.resultUsers.length > width" justify="center" style="height: 100px">
|
||||
<div
|
||||
v-for="user in result.resultUsers"
|
||||
:key="user.uId"
|
||||
title="抽奖结果"
|
||||
style="height: 100px; width: 100px; display: flex; flex-direction: column; align-items: center; border-radius: 5px; border: #fff 1px solid; padding: 10px; margin: 10px"
|
||||
>
|
||||
<NSpace vertical>
|
||||
<img height="50" width="50" style="border-radius: 50%" :src="user.avatar + '@50h_50w'" referrerpolicy="no-referrer" />
|
||||
<NText style="font-size: large">
|
||||
{{ user.name }}
|
||||
</NText>
|
||||
</NSpace>
|
||||
</div>
|
||||
</Vue3Marquee>
|
||||
<NSpace justify="center">
|
||||
<div
|
||||
v-for="user in result.resultUsers"
|
||||
:key="user.uId"
|
||||
title="抽奖结果"
|
||||
style="height: 100px; width: 100px; display: flex; flex-direction: column; align-items: center; border-radius: 5px; border: #fff 1px solid; padding: 10px; margin: 10px"
|
||||
>
|
||||
<img height="50" width="50" style="border-radius: 50%" :src="user.avatar + '@50h_50w'" referrerpolicy="no-referrer" />
|
||||
<NText style="font-size: large; margin-top: 10px">
|
||||
{{ user.name }}
|
||||
</NText>
|
||||
</div>
|
||||
</NSpace>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.lottery-background {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
min-height: 100px !important;
|
||||
min-width: 100px !important;
|
||||
background-color: #0f0f0f48 !important;
|
||||
border-radius: 10px !important;
|
||||
color: white !important;
|
||||
}
|
||||
.lottery-header {
|
||||
margin: 0 !important;
|
||||
color: #fff !important;
|
||||
text-align: center !important;
|
||||
font-size: 24px !important;
|
||||
font-weight: bold !important;
|
||||
text-shadow: 0 0 10px #ca7b7b6e, 0 0 20px #ffffff8e, 0 0 30px #61606086, 0 0 40px rgba(64, 156, 179, 0.555) !important;
|
||||
}
|
||||
.lottery-header-count {
|
||||
color: #ffffffbd !important;
|
||||
text-align: center !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
.lottery-divider {
|
||||
margin: -10px 10px -10px 10px !important;
|
||||
width: 90% !important;
|
||||
}
|
||||
.n-divider__line {
|
||||
background-color: #ffffffd5 !important;
|
||||
}
|
||||
.lottery-content {
|
||||
background-color: #0f0f0f4f !important;
|
||||
margin: 10px !important;
|
||||
padding: 10px !important;
|
||||
height: 100% !important;
|
||||
border-radius: 10px !important;
|
||||
}
|
||||
.lottery-list-item {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
gap: 10px !important;
|
||||
transition: color 0.3s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
|
||||
}
|
||||
.lottery-avatar {
|
||||
height: 30px !important;
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
</style>
|
||||
@@ -1,15 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, h, onMounted, ref } from 'vue'
|
||||
import { computed, h, onMounted, onUnmounted, ref } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { QueryPostAPI } from '@/api/query'
|
||||
import { OPEN_LIVE_API_URL } from '@/data/constants'
|
||||
import { LotteryUserInfo, OpenLiveInfo } from '@/api/api-models'
|
||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||
import { LOTTERY_API_URL, OPEN_LIVE_API_URL } from '@/data/constants'
|
||||
import { LotteryUserInfo, OpenLiveInfo, OpenLiveLotteryType, OpenLiveLotteryUserInfo } from '@/api/api-models'
|
||||
import {
|
||||
NAlert,
|
||||
NAvatar,
|
||||
NButton,
|
||||
NCard,
|
||||
NCheckbox,
|
||||
NCollapse,
|
||||
NCollapseItem,
|
||||
NCollapseTransition,
|
||||
NDivider,
|
||||
NEmpty,
|
||||
@@ -21,6 +23,7 @@ import {
|
||||
NInputGroupLabel,
|
||||
NInputNumber,
|
||||
NLayoutContent,
|
||||
NLi,
|
||||
NList,
|
||||
NListItem,
|
||||
NModal,
|
||||
@@ -33,6 +36,7 @@ import {
|
||||
NTag,
|
||||
NTime,
|
||||
NTooltip,
|
||||
NUl,
|
||||
useMessage,
|
||||
useNotification,
|
||||
} from 'naive-ui'
|
||||
@@ -41,6 +45,7 @@ import ChatClientDirectOpenLive from '@/data/chat/ChatClientDirectOpenLive.js'
|
||||
import { useLocalStorage, useStorage } from '@vueuse/core'
|
||||
import { format } from 'date-fns'
|
||||
import { Delete24Filled, Info24Filled } from '@vicons/fluent'
|
||||
import LiveLotteryOBS from '../obs/LiveLotteryOBS.vue'
|
||||
|
||||
interface AuthInfo {
|
||||
Timestamp: string
|
||||
@@ -49,18 +54,6 @@ interface AuthInfo {
|
||||
Caller: string
|
||||
CodeSign: string
|
||||
}
|
||||
interface OpenLiveLotteryBaseUserInfo {
|
||||
name: string
|
||||
uId: number
|
||||
level?: number
|
||||
avatar: string
|
||||
}
|
||||
interface OpenLiveLotteryUserInfo extends OpenLiveLotteryBaseUserInfo {
|
||||
fans_medal_level: number
|
||||
fans_medal_name: string //粉丝勋章名
|
||||
fans_medal_wearing_status: boolean //该房间粉丝勋章佩戴情况
|
||||
guard_level: number
|
||||
}
|
||||
interface LotteryOption {
|
||||
resultCount: number
|
||||
lotteryType: 'single' | 'half'
|
||||
@@ -75,7 +68,7 @@ interface LotteryOption {
|
||||
giftName?: string
|
||||
}
|
||||
interface LotteryHistory {
|
||||
users: OpenLiveLotteryBaseUserInfo[]
|
||||
users: OpenLiveLotteryUserInfo[]
|
||||
time: number
|
||||
}
|
||||
const CMD_CALLBACK_MAP = {
|
||||
@@ -102,6 +95,9 @@ const notification = useNotification()
|
||||
|
||||
const authInfo = ref<AuthInfo>()
|
||||
const authResult = ref<OpenLiveInfo | null>(null)
|
||||
const code = computed(() => {
|
||||
return authInfo.value?.Code ?? accountInfo.value?.biliAuthCode
|
||||
})
|
||||
|
||||
const originUsers = ref<OpenLiveLotteryUserInfo[]>([])
|
||||
const currentUsers = ref<OpenLiveLotteryUserInfo[]>([])
|
||||
@@ -111,6 +107,7 @@ const isLottering = ref(false)
|
||||
const isLotteried = ref(false)
|
||||
const isConnected = ref(false)
|
||||
const showModal = ref(false)
|
||||
const showOBSModal = ref(false)
|
||||
|
||||
let chatClient: any
|
||||
|
||||
@@ -129,6 +126,30 @@ async function get() {
|
||||
}
|
||||
return null
|
||||
}
|
||||
async function getUsers() {
|
||||
try {
|
||||
const data = await QueryGetAPI<OpenLiveLotteryUserInfo[]>(LOTTERY_API_URL + 'live/get-users', {
|
||||
code: code.value,
|
||||
})
|
||||
if (data.code == 200) {
|
||||
console.log('[OPEN-LIVE] 已获历史抽奖用户')
|
||||
return data.data
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
return null
|
||||
}
|
||||
function updateUsers() {
|
||||
QueryPostAPI(LOTTERY_API_URL + 'live/update-users', {
|
||||
code: code.value,
|
||||
users: originUsers.value,
|
||||
resultUsers: resultUsers.value,
|
||||
type: isLotteried.value ? OpenLiveLotteryType.Result : OpenLiveLotteryType.Waiting,
|
||||
}).catch((err) => {
|
||||
console.error('[OPEN-LIVE] 更新历史抽奖用户失败: ' + err)
|
||||
})
|
||||
}
|
||||
async function start() {
|
||||
if (!chatClient) {
|
||||
const auth = await get()
|
||||
@@ -160,6 +181,7 @@ function addUser(user: OpenLiveLotteryUserInfo, danmu: any) {
|
||||
originUsers.value.push(user)
|
||||
currentUsers.value.push(user)
|
||||
console.log(`[OPEN-LIVE-Lottery] ${user.name} 添加到队列中`)
|
||||
updateUsers()
|
||||
} else {
|
||||
console.log(`[OPEN-LIVE-Lottery] ${user.name} 因不符合条件而被忽略`)
|
||||
}
|
||||
@@ -264,6 +286,7 @@ function onFinishLottery() {
|
||||
message.success('已保存至历史')
|
||||
},
|
||||
})
|
||||
updateUsers()
|
||||
lotteryHistory.value.push({
|
||||
users: currentUsers.value ?? [],
|
||||
time: Date.now(),
|
||||
@@ -272,6 +295,7 @@ function onFinishLottery() {
|
||||
function reset() {
|
||||
currentUsers.value = JSON.parse(JSON.stringify(originUsers.value))
|
||||
isLotteried.value = false
|
||||
updateUsers()
|
||||
}
|
||||
function clear() {
|
||||
originUsers.value = []
|
||||
@@ -279,10 +303,14 @@ function clear() {
|
||||
resultUsers.value = []
|
||||
currentUsers.value = []
|
||||
message.success('已清空队列')
|
||||
|
||||
updateUsers()
|
||||
}
|
||||
function removeUser(user: OpenLiveLotteryUserInfo) {
|
||||
currentUsers.value = currentUsers.value.filter((u) => u.uId != user.uId)
|
||||
originUsers.value = originUsers.value.filter((u) => u.uId != user.uId)
|
||||
|
||||
updateUsers()
|
||||
}
|
||||
|
||||
function onDanmaku(command: any) {
|
||||
@@ -324,16 +352,51 @@ function continueLottery() {
|
||||
message.info('开始监听')
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
let timer: any
|
||||
onMounted(async () => {
|
||||
authInfo.value = route.query as unknown as AuthInfo
|
||||
if (authInfo.value?.Code) {
|
||||
const users = (await getUsers()) ?? []
|
||||
originUsers.value = users
|
||||
currentUsers.value = JSON.parse(JSON.stringify(users))
|
||||
console.log('[OPEN-LIVE-Lottery] 从历史记录中加载 ' + users.length + ' 位用户')
|
||||
if (users.length > 0) {
|
||||
message.info('从历史记录中加载 ' + users.length + ' 位用户')
|
||||
}
|
||||
}
|
||||
timer = setInterval(updateUsers, 1000 * 10)
|
||||
|
||||
const data: OpenLiveLotteryUserInfo[] = []
|
||||
|
||||
for (let i = 0; i < 13; i++) {
|
||||
const userInfo: OpenLiveLotteryUserInfo = {
|
||||
name: `User ${i + 1}`,
|
||||
uId: i + 1,
|
||||
level: i + 10,
|
||||
avatar: `http://i0.hdslb.com/bfs/face/284f87fba8ff1b9c9564925747c7dc456df65cca.jpg`,
|
||||
fans_medal_level: i + 1,
|
||||
fans_medal_name: `Fans Medal ${i + 1}`,
|
||||
fans_medal_wearing_status: true,
|
||||
guard_level: i + 5,
|
||||
}
|
||||
|
||||
data.push(userInfo)
|
||||
}
|
||||
originUsers.value = data
|
||||
currentUsers.value = JSON.parse(JSON.stringify(data))
|
||||
})
|
||||
onUnmounted(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NLayoutContent style="height: 100vh">
|
||||
<NLayoutContent style="height: 100vh; padding: 20px">
|
||||
<NResult v-if="!authInfo?.Code && !accountInfo" status="403" title="403" description="该页面只能从饭贩访问或者注册用户使用" />
|
||||
<template v-else>
|
||||
<NCard style="margin: 20px">
|
||||
<NCard>
|
||||
<template #header>
|
||||
直播抽奖
|
||||
<NDivider vertical />
|
||||
@@ -349,6 +412,7 @@ onMounted(() => {
|
||||
连接直播间
|
||||
</NButton>
|
||||
<NButton type="info" @click="showModal = true" size="small"> 抽奖历史</NButton>
|
||||
<NButton type="success" @click="showOBSModal = true" size="small"> OBS组件</NButton>
|
||||
</NSpace>
|
||||
</NCard>
|
||||
<NCard size="small" embedded title="抽奖选项">
|
||||
@@ -503,5 +567,27 @@ onMounted(() => {
|
||||
</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">
|
||||
<NAlert title="这是什么? " type="info"> 将等待队列以及结果显示在OBS中 </NAlert>
|
||||
<NDivider> 浏览 </NDivider>
|
||||
<div style="height: 400px; width: 250px; position: relative; margin: 0 auto">
|
||||
<LiveLotteryOBS :code="code" />
|
||||
</div>
|
||||
<br />
|
||||
<NInput :value="'https://localhost:5173/obs/live-lottery?code=' + code" />
|
||||
<NDivider />
|
||||
<NCollapse>
|
||||
<NCollapseItem title="使用说明">
|
||||
<NUl>
|
||||
<NLi>在 OBS 来源中添加源, 选择 浏览器</NLi>
|
||||
<NLi>在 URL 栏填入上方链接</NLi>
|
||||
<NLi>根据自己的需要调整宽度和高度</NLi>
|
||||
<NLi>完事</NLi>
|
||||
</NUl>
|
||||
</NCollapseItem>
|
||||
</NCollapse>
|
||||
|
||||
<NDivider />
|
||||
</NModal>
|
||||
</NLayoutContent>
|
||||
</template>
|
||||
|
||||
11
src/views/view/songListTemplate/SimpleSongListTemplate.vue
Normal file
11
src/views/view/songListTemplate/SimpleSongListTemplate.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import { NGridItem,NGrid } from 'naive-ui';
|
||||
</script>
|
||||
<template>
|
||||
<NGrid>
|
||||
<NGridItem>
|
||||
|
||||
</NGridItem>
|
||||
</NGrid>
|
||||
</template>
|
||||
@@ -3362,6 +3362,11 @@ vue3-aplayer@^1.7.3:
|
||||
dependencies:
|
||||
vue-loader "^16.1.2"
|
||||
|
||||
vue3-marquee@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/vue3-marquee/-/vue3-marquee-4.1.0.tgz#145baa65dd40059358e4079d51ab596c2ccf1299"
|
||||
integrity sha512-AkvpNC6+7CwvIBgiAr8qMs1XvhGhfSS2ahlMEp80YXAmDOP8nDdn/smQ6eWtusf+hLX21yTaSOoKGcill4bCRg==
|
||||
|
||||
vue@^3.2.13, vue@^3.2.45:
|
||||
version "3.3.7"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.3.7.tgz#972a218682443a3819d121261b2bff914417f4f0"
|
||||
|
||||
Reference in New Issue
Block a user