mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
update
This commit is contained in:
@@ -15,12 +15,15 @@
|
|||||||
"@vueuse/integrations": "^10.1.2",
|
"@vueuse/integrations": "^10.1.2",
|
||||||
"@vueuse/router": "^10.1.2",
|
"@vueuse/router": "^10.1.2",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
|
"date-fns": "^2.30.0",
|
||||||
|
"echarts": "^5.4.3",
|
||||||
"grapheme-splitter": "^1.0.4",
|
"grapheme-splitter": "^1.0.4",
|
||||||
"linqts": "^1.15.0",
|
"linqts": "^1.15.0",
|
||||||
"universal-cookie": "^4.0.4",
|
"universal-cookie": "^4.0.4",
|
||||||
"vite": "^4.3.9",
|
"vite": "^4.3.9",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
|
"vue-echarts": "^6.6.1",
|
||||||
"vue-meta": "^3.0.0-alpha.10",
|
"vue-meta": "^3.0.0-alpha.10",
|
||||||
"vue-request": "^2.0.3",
|
"vue-request": "^2.0.3",
|
||||||
"vue-router": "4",
|
"vue-router": "4",
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import { ref } from 'vue'
|
|||||||
import { useRouteParams } from '@vueuse/router'
|
import { useRouteParams } from '@vueuse/router'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
export const USERS = ref<{ [uId: number]: UserInfo }>({})
|
export const USERS = ref<{ [id: string]: UserInfo }>({})
|
||||||
|
|
||||||
export async function useUser(id: number | undefined = undefined) {
|
export async function useUser(id: string | undefined = undefined) {
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
id ??= Number(route.params.id)
|
id ??= route.params.id.toString()
|
||||||
if (id) {
|
if (id) {
|
||||||
if (!USERS.value[id]) {
|
if (!USERS.value[id]) {
|
||||||
const result = await GetInfo(id)
|
const result = await GetInfo(id)
|
||||||
@@ -23,16 +23,18 @@ export async function useUser(id: number | undefined = undefined) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
export async function useUserWithUId(id: number) {
|
export async function useUserWithUId(id: number) {
|
||||||
if (!USERS.value[id]) {
|
if (!USERS.value[id.toString()]) {
|
||||||
const result = await GetInfo(id)
|
const result = await QueryGetAPI<UserInfo>(`${USER_API_URL}info`, {
|
||||||
|
uId: id,
|
||||||
|
})
|
||||||
if (result.code == 200) {
|
if (result.code == 200) {
|
||||||
USERS.value[id] = result.data
|
USERS.value[id.toString()] = result.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return USERS.value[id]
|
return USERS.value[id.toString()]
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function GetInfo(id: number): Promise<APIRoot<UserInfo>> {
|
export async function GetInfo(id: string): Promise<APIRoot<UserInfo>> {
|
||||||
return QueryGetAPI<UserInfo>(`${USER_API_URL}info`, {
|
return QueryGetAPI<UserInfo>(`${USER_API_URL}info`, {
|
||||||
id: id,
|
id: id,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -124,9 +124,7 @@ function onregisterButtonClick(e: MouseEvent) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function onLoginButtonClick(e: MouseEvent) {
|
function onLoginButtonClick() {
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
formRef.value?.validate().then(async () => {
|
formRef.value?.validate().then(async () => {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
await QueryPostAPI<{
|
await QueryPostAPI<{
|
||||||
@@ -178,7 +176,7 @@ function onLoginButtonClick(e: MouseEvent) {
|
|||||||
<NInput v-model:value="loginModel.account" />
|
<NInput v-model:value="loginModel.account" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="password" label="密码">
|
<NFormItem path="password" label="密码">
|
||||||
<NInput v-model:value="loginModel.password" type="password" @input="onPasswordInput" @keydown.enter.prevent />
|
<NInput v-model:value="loginModel.password" type="password" @input="onPasswordInput" @keydown.enter="onLoginButtonClick"/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NForm>
|
</NForm>
|
||||||
<NSpace vertical justify="center" align="center">
|
<NSpace vertical justify="center" align="center">
|
||||||
|
|||||||
@@ -146,9 +146,17 @@ const authorColumn = ref<DataTableBaseColumn<SongsInfo>>({
|
|||||||
},
|
},
|
||||||
filterOptions: authorsOptions.value,
|
filterOptions: authorsOptions.value,
|
||||||
render(data) {
|
render(data) {
|
||||||
return h(NSpace, { size: 5 }, () => data.author.map((a) => h(NButton, { size: 'tiny', type: 'info', secondary: true, onClick: () => (authorColumn.value.filterOptionValue = a) }, () => a)))
|
return h(NSpace, { size: 5 }, () => data.author.map((a) => h(NButton, { size: 'tiny', type: 'info', secondary: true, onClick: () => onAuthorClick(a) }, () => a)))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const onAuthorClick = (author: string) => {
|
||||||
|
if(authorColumn.value.filterOptionValue == author){
|
||||||
|
authorColumn.value.filterOptionValue = undefined
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
authorColumn.value.filterOptionValue = author
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function createColumns(): DataTableColumns<SongsInfo> {
|
function createColumns(): DataTableColumns<SongsInfo> {
|
||||||
authorColumn.value.filterOptions = authorsOptions.value
|
authorColumn.value.filterOptions = authorsOptions.value
|
||||||
@@ -405,7 +413,7 @@ onMounted(() => {
|
|||||||
<NCard embedded size="small">
|
<NCard embedded size="small">
|
||||||
<NInput placeholder="搜索歌曲" v-model:value="searchMusicKeyword" size="small" style="max-width: 150px" />
|
<NInput placeholder="搜索歌曲" v-model:value="searchMusicKeyword" size="small" style="max-width: 150px" />
|
||||||
</NCard>
|
</NCard>
|
||||||
<NDivider style="margin: 5px 0 5px 0"> 共 {{ songsInternal.length }} 首 </NDivider>
|
<NDivider style="margin: 5px 0 5px 0"> 共 {{ songsComputed.length }} 首 </NDivider>
|
||||||
<Transition>
|
<Transition>
|
||||||
<div v-if="aplayerMusic">
|
<div v-if="aplayerMusic">
|
||||||
<APlayer :music="aplayerMusic" autoplay />
|
<APlayer :music="aplayerMusic" autoplay />
|
||||||
@@ -434,7 +442,7 @@ onMounted(() => {
|
|||||||
<NSelect v-model:value="updateSongModel.language" multiple :options="songSelectOption" placeholder="可选" />
|
<NSelect v-model:value="updateSongModel.language" multiple :options="songSelectOption" placeholder="可选" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="tags" label="标签">
|
<NFormItem path="tags" label="标签">
|
||||||
<NSelect v-model:value="updateSongModel.tags" filterable multiple tag placeholder="可选,按回车确认" :show-arrow="false" :show="false" :options="tagsSelectOption" />
|
<NSelect v-model:value="updateSongModel.tags" filterable multiple clearable tag placeholder="可选,按回车确认" :options="tagsSelectOption" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="url" label="链接">
|
<NFormItem path="url" label="链接">
|
||||||
<NInput v-model:value="updateSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" :disabled="updateSongModel.from != SongFrom.Custom" />
|
<NInput v-model:value="updateSongModel.url" placeholder="可选, 后缀为mp3、wav、ogg时将会尝试播放, 否则会在新页面打开" :disabled="updateSongModel.from != SongFrom.Custom" />
|
||||||
|
|||||||
@@ -18,3 +18,4 @@ export const SONG_API_URL = `${BASE_API}song-list/`
|
|||||||
export const NOTIFACTION_API_URL = `${BASE_API}notifaction/`
|
export const NOTIFACTION_API_URL = `${BASE_API}notifaction/`
|
||||||
export const QUESTION_API_URL = `${BASE_API}qa/`
|
export const QUESTION_API_URL = `${BASE_API}qa/`
|
||||||
export const LOTTERY_API_URL = `${BASE_API}lottery/`
|
export const LOTTERY_API_URL = `${BASE_API}lottery/`
|
||||||
|
export const HISTORY_API_URL = `${BASE_API}history/`
|
||||||
|
|||||||
@@ -76,9 +76,14 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
component: () => import('@/views/manage/BiliVerifyView.vue'),
|
component: () => import('@/views/manage/BiliVerifyView.vue'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'setting',
|
path: 'history',
|
||||||
name: 'manage-setting',
|
name: 'manage-history',
|
||||||
component: () => import('@/views/manage/SettingsManageView.vue'),
|
component: () => import('@/views/manage/HistoryView.vue'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'schedule',
|
||||||
|
name: 'manage-schedule',
|
||||||
|
component: () => import('@/views/manage/ScheduleManageView.vue'),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import {
|
|||||||
useMessage,
|
useMessage,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { h, onMounted, ref } from 'vue'
|
import { h, onMounted, ref } from 'vue'
|
||||||
import { BrowsersOutline, Chatbox, Moon, MusicalNote, Sunny } from '@vicons/ionicons5'
|
import { BrowsersOutline, Chatbox, Moon, MusicalNote, Sunny, AnalyticsSharp } from '@vicons/ionicons5'
|
||||||
import { Lottery24Filled } from '@vicons/fluent'
|
import { CalendarClock24Filled, Lottery24Filled } from '@vicons/fluent'
|
||||||
import { isLoadingAccount, useAccount } from '@/api/account'
|
import { isLoadingAccount, useAccount } from '@/api/account'
|
||||||
import RegisterAndLogin from '@/components/RegisterAndLogin.vue'
|
import RegisterAndLogin from '@/components/RegisterAndLogin.vue'
|
||||||
import { RouterLink } from 'vue-router'
|
import { RouterLink } from 'vue-router'
|
||||||
@@ -48,6 +48,36 @@ function renderIcon(icon: unknown) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const menuOptions = [
|
const menuOptions = [
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'manage-history',
|
||||||
|
},
|
||||||
|
disabled: !accountInfo.value?.isEmailVerified,
|
||||||
|
},
|
||||||
|
{ default: () => '历史' }
|
||||||
|
),
|
||||||
|
key: 'manage-history',
|
||||||
|
icon: renderIcon(AnalyticsSharp),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h(
|
||||||
|
RouterLink,
|
||||||
|
{
|
||||||
|
to: {
|
||||||
|
name: 'manage-schedule',
|
||||||
|
},
|
||||||
|
disabled: !accountInfo.value?.isEmailVerified,
|
||||||
|
},
|
||||||
|
{ default: () => '日程' }
|
||||||
|
),
|
||||||
|
key: 'manage-schedule',
|
||||||
|
icon: renderIcon(CalendarClock24Filled),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: () =>
|
label: () =>
|
||||||
h(
|
h(
|
||||||
@@ -196,9 +226,7 @@ onMounted(() => {
|
|||||||
<RegisterAndLogin style="max-width: 500px; min-width: 350px" />
|
<RegisterAndLogin style="max-width: 500px; min-width: 350px" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<NSpin :loading="isLoadingAccount">
|
<NSpin :loading="isLoadingAccount"> 正在请求账户数据... </NSpin>
|
||||||
正在请求账户数据...
|
|
||||||
</NSpin>
|
|
||||||
</template>
|
</template>
|
||||||
</NLayoutContent>
|
</NLayoutContent>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
NModal,
|
NModal,
|
||||||
NEllipsis,
|
NEllipsis,
|
||||||
MenuOption,
|
MenuOption,
|
||||||
|
NSpin,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { computed, h, onMounted, ref } from 'vue'
|
import { computed, h, onMounted, ref } from 'vue'
|
||||||
import { BookOutline as BookIcon, Chatbox, Home, Moon, MusicalNote, PersonOutline as PersonIcon, Sunny, WineOutline as WineIcon } from '@vicons/ionicons5'
|
import { BookOutline as BookIcon, Chatbox, Home, Moon, MusicalNote, PersonOutline as PersonIcon, Sunny, WineOutline as WineIcon } from '@vicons/ionicons5'
|
||||||
@@ -30,7 +31,7 @@ import { isDarkMode } from '@/Utils'
|
|||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const id = computed(() => {
|
const id = computed(() => {
|
||||||
return Number(route.params.id)
|
return route.params.id
|
||||||
})
|
})
|
||||||
const themeType = useStorage('Settings.Theme', ThemeType.Auto);
|
const themeType = useStorage('Settings.Theme', ThemeType.Auto);
|
||||||
|
|
||||||
@@ -160,11 +161,14 @@ onMounted(async () => {
|
|||||||
</NLayoutSider>
|
</NLayoutSider>
|
||||||
<NLayout style="height: 100%">
|
<NLayout style="height: 100%">
|
||||||
<div class="viewer-page-content" :style="`box-shadow:${isDarkMode() ? 'rgb(28 28 28 / 9%) 5px 5px 6px inset, rgba(139, 139, 139, 0.09) -5px -5px 6px inset' : 'inset 5px 5px 6px #8b8b8b17, inset -5px -5px 6px #8b8b8b17;'}`">
|
<div class="viewer-page-content" :style="`box-shadow:${isDarkMode() ? 'rgb(28 28 28 / 9%) 5px 5px 6px inset, rgba(139, 139, 139, 0.09) -5px -5px 6px inset' : 'inset 5px 5px 6px #8b8b8b17, inset -5px -5px 6px #8b8b8b17;'}`">
|
||||||
<RouterView v-slot="{ Component }">
|
<RouterView v-if="userInfo" v-slot="{ Component }">
|
||||||
<KeepAlive>
|
<KeepAlive>
|
||||||
<component :is="Component" :bili-info="biliUserInfo" />
|
<component :is="Component" :bili-info="biliUserInfo" :user-info="userInfo" />
|
||||||
</KeepAlive>
|
</KeepAlive>
|
||||||
</RouterView>
|
</RouterView>
|
||||||
|
<template v-else>
|
||||||
|
<NSpin show/>
|
||||||
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</NLayout>
|
</NLayout>
|
||||||
</NLayout>
|
</NLayout>
|
||||||
|
|||||||
@@ -1,2 +1,251 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
</script>
|
import { useAccount } from '@/api/account'
|
||||||
|
import { QueryGetAPI } from '@/api/query'
|
||||||
|
import { HISTORY_API_URL } from '@/data/constants'
|
||||||
|
import { NCard, useMessage } from 'naive-ui'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { use } from 'echarts/core'
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
|
import { LineChart } from 'echarts/charts'
|
||||||
|
import { TitleComponent, TooltipComponent, LegendComponent, GridComponent, DataZoomComponent } from 'echarts/components'
|
||||||
|
import VChart, { THEME_KEY } from 'vue-echarts'
|
||||||
|
import { format } from 'date-fns'
|
||||||
|
|
||||||
|
use([CanvasRenderer, LineChart, TitleComponent, TooltipComponent, LegendComponent, GridComponent, DataZoomComponent, LineChart])
|
||||||
|
|
||||||
|
const accountInfo = useAccount()
|
||||||
|
const message = useMessage()
|
||||||
|
|
||||||
|
const fansHistory = ref<{ time: number; count: number }[]>()
|
||||||
|
const guardHistory = ref<{ time: number; count: number }[]>()
|
||||||
|
const fansOption = ref()
|
||||||
|
const guardsOption = ref()
|
||||||
|
|
||||||
|
async function getFansHistory() {
|
||||||
|
await QueryGetAPI<
|
||||||
|
{
|
||||||
|
time: number
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
>(HISTORY_API_URL + 'fans', {
|
||||||
|
id: accountInfo.value?.id,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (data.code == 200) {
|
||||||
|
fansHistory.value = data.data
|
||||||
|
} else {
|
||||||
|
message.error('加载失败: ' + data.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err)
|
||||||
|
message.error('加载失败')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async function getGuardsHistory() {
|
||||||
|
await QueryGetAPI<
|
||||||
|
{
|
||||||
|
time: number
|
||||||
|
count: number
|
||||||
|
}[]
|
||||||
|
>(HISTORY_API_URL + 'guards', {
|
||||||
|
id: accountInfo.value?.id,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (data.code == 200) {
|
||||||
|
guardHistory.value = data.data
|
||||||
|
} else {
|
||||||
|
message.error('加载失败: ' + data.message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err)
|
||||||
|
message.error('加载失败')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function isSameDay(time1: number, time2: number) {
|
||||||
|
const time1Date = new Date(time1)
|
||||||
|
const time2Date = new Date(time2)
|
||||||
|
return time1Date.getFullYear() === time2Date.getFullYear() && time1Date.getMonth() === time2Date.getMonth() && time1Date.getDate() === time2Date.getDate()
|
||||||
|
}
|
||||||
|
function getOptions() {
|
||||||
|
let fansIncreacement = [] as { time: number; count: number; timeString: string }[]
|
||||||
|
let guards = [] as { time: number; count: number; timeString: string }[]
|
||||||
|
|
||||||
|
let fansIncreacementLastHour = 0
|
||||||
|
let lastHourFans = 0
|
||||||
|
fansHistory.value?.forEach((f) => {
|
||||||
|
if (!isSameDay(f.time, fansIncreacementLastHour)) {
|
||||||
|
fansIncreacement.push({
|
||||||
|
time: fansIncreacementLastHour,
|
||||||
|
count: fansIncreacementLastHour == 0 ? 0 : f.count - lastHourFans,
|
||||||
|
//将timeString转换为yyyy-MM-dd HH
|
||||||
|
timeString: format(f.time, 'yyyy-MM-dd'),
|
||||||
|
})
|
||||||
|
fansIncreacementLastHour = f.time
|
||||||
|
lastHourFans = f.count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let lastDayGuards = 0
|
||||||
|
let lastDay = 0
|
||||||
|
guardHistory.value?.forEach((g) => {
|
||||||
|
if (!isSameDay(g.time, lastDayGuards)) {
|
||||||
|
guards.push({
|
||||||
|
time: lastDayGuards,
|
||||||
|
count: lastDay == 0 ? 0 : g.count - lastDayGuards,
|
||||||
|
//将timeString转换为yyyy-MM-dd HH
|
||||||
|
timeString: format(g.time, 'yyyy-MM-dd'),
|
||||||
|
})
|
||||||
|
lastDay = g.time
|
||||||
|
lastDayGuards = g.count
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fansOption.value = {
|
||||||
|
title: {
|
||||||
|
text: '粉丝数',
|
||||||
|
left: 'left',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: {
|
||||||
|
alignWithLabel: true,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
onZero: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#EE6666',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// prettier-ignore
|
||||||
|
data: fansIncreacement.map((f) => f.timeString),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: {
|
||||||
|
alignWithLabel: true,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
onZero: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#5470C6',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// prettier-ignore
|
||||||
|
data: fansHistory.value?.map(f => format(f.time, 'yyyy-MM-dd HH:mm')),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '粉丝数',
|
||||||
|
type: 'line',
|
||||||
|
xAxisIndex: 1,
|
||||||
|
yAxisIndex: 1,
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
},
|
||||||
|
data: fansHistory.value?.map((f) => f.count),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '增量 /日',
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
showSymbol: false,
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
},
|
||||||
|
data: fansIncreacement.map((f) => f.count),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
show: true,
|
||||||
|
realtime: true,
|
||||||
|
start: 0,
|
||||||
|
end: 100,
|
||||||
|
xAxisIndex: [0, 1],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
guardsOption.value = {
|
||||||
|
title: {
|
||||||
|
text: '舰长数',
|
||||||
|
left: 'left',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
},
|
||||||
|
legend: {},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
axisTick: {
|
||||||
|
alignWithLabel: true,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
onZero: false,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#EE6666',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// prettier-ignore
|
||||||
|
data: guards.map((f) => f.timeString ),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '舰长数',
|
||||||
|
type: 'line',
|
||||||
|
step: 'start',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
},
|
||||||
|
data: guards.map((f) => f.count),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dataZoom: [
|
||||||
|
{
|
||||||
|
show: true,
|
||||||
|
realtime: true,
|
||||||
|
start: 0,
|
||||||
|
end: 100,
|
||||||
|
xAxisIndex: [0, 1],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await getFansHistory()
|
||||||
|
await getGuardsHistory()
|
||||||
|
getOptions()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NCard size="small">
|
||||||
|
<VChart :option="fansOption" style="height: 200px" />
|
||||||
|
<VChart :option="guardsOption" style="height: 200px" />
|
||||||
|
</NCard>
|
||||||
|
</template>
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { NavigateToNewTab } from '@/Utils'
|
||||||
import { LotteryUserInfo } from '@/api/api-models'
|
import { LotteryUserInfo } from '@/api/api-models'
|
||||||
import { QueryGetAPI } from '@/api/query'
|
import { QueryGetAPI } from '@/api/query'
|
||||||
import { LOTTERY_API_URL, TURNSTILE_KEY } from '@/data/constants'
|
import { LOTTERY_API_URL, TURNSTILE_KEY } from '@/data/constants'
|
||||||
import { useLocalStorage } from '@vueuse/core'
|
import { useLocalStorage, useStorage } from '@vueuse/core'
|
||||||
import { randomInt } from 'crypto'
|
import { randomInt } from 'crypto'
|
||||||
|
import { format } from 'date-fns'
|
||||||
import { List } from 'linqts'
|
import { List } from 'linqts'
|
||||||
import {
|
import {
|
||||||
NAvatar,
|
NAvatar,
|
||||||
@@ -13,22 +15,30 @@ import {
|
|||||||
NCollapseTransition,
|
NCollapseTransition,
|
||||||
NCountdown,
|
NCountdown,
|
||||||
NDivider,
|
NDivider,
|
||||||
|
NEmpty,
|
||||||
NGrid,
|
NGrid,
|
||||||
NGridItem,
|
NGridItem,
|
||||||
NInput,
|
NInput,
|
||||||
NInputGroup,
|
NInputGroup,
|
||||||
NInputGroupLabel,
|
NInputGroupLabel,
|
||||||
NInputNumber,
|
NInputNumber,
|
||||||
|
NList,
|
||||||
|
NListItem,
|
||||||
|
NModal,
|
||||||
NRadioButton,
|
NRadioButton,
|
||||||
NRadioGroup,
|
NRadioGroup,
|
||||||
|
NScrollbar,
|
||||||
NSpace,
|
NSpace,
|
||||||
NTabPane,
|
NTabPane,
|
||||||
NTabs,
|
NTabs,
|
||||||
NTag,
|
NTag,
|
||||||
|
NTime,
|
||||||
|
NTooltip,
|
||||||
useMessage,
|
useMessage,
|
||||||
|
useNotification,
|
||||||
} from 'naive-ui'
|
} from 'naive-ui'
|
||||||
import { breadcrumbLight } from 'naive-ui/es/breadcrumb/styles'
|
import { breadcrumbLight } from 'naive-ui/es/breadcrumb/styles'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, h, ref } from 'vue'
|
||||||
import VueTurnstile from 'vue-turnstile'
|
import VueTurnstile from 'vue-turnstile'
|
||||||
|
|
||||||
interface TempLotteryResponseModel {
|
interface TempLotteryResponseModel {
|
||||||
@@ -40,20 +50,40 @@ interface LotteryOption {
|
|||||||
resultCount: number
|
resultCount: number
|
||||||
lotteryType: 'single' | 'half'
|
lotteryType: 'single' | 'half'
|
||||||
needVIP: boolean
|
needVIP: boolean
|
||||||
|
needFanCard: boolean
|
||||||
|
needGuard: boolean
|
||||||
|
needCharge: boolean
|
||||||
|
fanCardLevel: number
|
||||||
|
}
|
||||||
|
interface LotteryHistory {
|
||||||
|
users: LotteryUserInfo[]
|
||||||
|
time: number
|
||||||
|
type: 'comment' | 'forward'
|
||||||
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const lotteryHistory = useStorage<LotteryHistory[]>('LotteryHistory', [])
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
const notification = useNotification()
|
||||||
const token = ref()
|
const token = ref()
|
||||||
const turnstile = ref()
|
const turnstile = ref()
|
||||||
const defaultOption = {
|
const defaultOption = {
|
||||||
resultCount: 1,
|
resultCount: 1,
|
||||||
lotteryType: 'single',
|
lotteryType: 'single',
|
||||||
needVIP: false,
|
needVIP: false,
|
||||||
|
needFanCard: false,
|
||||||
|
needGuard: false,
|
||||||
|
needCharge: false,
|
||||||
|
fanCardLevel: 1,
|
||||||
} as LotteryOption
|
} as LotteryOption
|
||||||
const lotteryOption = useLocalStorage('Settings.LotteryOption', defaultOption)
|
const lotteryOption = useLocalStorage('Settings.LotteryOption', defaultOption)
|
||||||
|
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const isLottering = ref(false)
|
const isLottering = ref(false)
|
||||||
|
const isLotteried = ref(false)
|
||||||
|
|
||||||
|
const showModal = ref(false)
|
||||||
|
|
||||||
const inputDynamic = ref<string>()
|
const inputDynamic = ref<string>()
|
||||||
const inputDynamicId = computed(() => {
|
const inputDynamicId = computed(() => {
|
||||||
@@ -79,10 +109,15 @@ const originCommentUsers = ref<TempLotteryResponseModel>()
|
|||||||
const originForwardUsers = ref<TempLotteryResponseModel>()
|
const originForwardUsers = ref<TempLotteryResponseModel>()
|
||||||
const currentType = ref<'comment' | 'forward'>('comment')
|
const currentType = ref<'comment' | 'forward'>('comment')
|
||||||
|
|
||||||
|
const resultUsers = ref<LotteryUserInfo[]>()
|
||||||
|
|
||||||
const commentUsers = ref<TempLotteryResponseModel>()
|
const commentUsers = ref<TempLotteryResponseModel>()
|
||||||
const forwardUsers = ref<TempLotteryResponseModel>()
|
const forwardUsers = ref<TempLotteryResponseModel>()
|
||||||
|
|
||||||
const currentUsers = computed(() => {
|
const currentUsers = computed(() => {
|
||||||
|
return getCurrentUsers()
|
||||||
|
})
|
||||||
|
function getCurrentUsers() {
|
||||||
switch (currentType.value) {
|
switch (currentType.value) {
|
||||||
case 'comment': {
|
case 'comment': {
|
||||||
return commentUsers.value
|
return commentUsers.value
|
||||||
@@ -92,6 +127,9 @@ const currentUsers = computed(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
|
}
|
||||||
|
const validUsers = computed(() => {
|
||||||
|
return currentUsers.value?.users.filter((u) => isUserValid(u))
|
||||||
})
|
})
|
||||||
|
|
||||||
async function onGet() {
|
async function onGet() {
|
||||||
@@ -118,7 +156,7 @@ async function getCommentsUsers() {
|
|||||||
)
|
)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
originCommentUsers.value = data.data
|
originCommentUsers.value = JSON.parse(JSON.stringify(data.data))
|
||||||
commentUsers.value = data.data
|
commentUsers.value = data.data
|
||||||
isCommentCountDown.value = false
|
isCommentCountDown.value = false
|
||||||
} else {
|
} else {
|
||||||
@@ -145,7 +183,7 @@ async function getForwardUsers() {
|
|||||||
)
|
)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
originForwardUsers.value = data.data
|
originForwardUsers.value = JSON.parse(JSON.stringify(data.data))
|
||||||
forwardUsers.value = data.data
|
forwardUsers.value = data.data
|
||||||
isCommentCountDown.value = false
|
isCommentCountDown.value = false
|
||||||
} else {
|
} else {
|
||||||
@@ -164,20 +202,38 @@ async function getForwardUsers() {
|
|||||||
function getRandomInt(max: number) {
|
function getRandomInt(max: number) {
|
||||||
return Math.floor(Math.random() * max)
|
return Math.floor(Math.random() * max)
|
||||||
}
|
}
|
||||||
|
function isUserValid(u: LotteryUserInfo) {
|
||||||
|
if (lotteryOption.value.needVIP) {
|
||||||
|
if (u.isVIP != true) return false
|
||||||
|
}
|
||||||
|
if (lotteryOption.value.needFanCard) {
|
||||||
|
if ((u.card?.level ?? -1) < lotteryOption.value.fanCardLevel) return false
|
||||||
|
}
|
||||||
|
if (lotteryOption.value.needGuard) {
|
||||||
|
if (u.card?.isGuard != true) return false
|
||||||
|
}
|
||||||
|
if (lotteryOption.value.needCharge) {
|
||||||
|
if (u.card?.isCharge != true) return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
function startLottery() {
|
function startLottery() {
|
||||||
if (!isLottering.value && currentUsers.value) {
|
if (!isLottering.value && currentUsers.value) {
|
||||||
isLottering.value = true
|
isLottering.value = true
|
||||||
try {
|
try {
|
||||||
const data = currentUsers.value
|
const data = currentUsers.value
|
||||||
const users = data.users.filter((u) => {
|
if ((validUsers.value?.length ?? -1) < lotteryOption.value.resultCount) {
|
||||||
if (lotteryOption.value.needVIP) {
|
message.warning('符合条件的抽奖人数达不到抽选人数')
|
||||||
return u.isVIP == true
|
isLottering.value = false
|
||||||
}
|
return
|
||||||
})
|
}
|
||||||
|
|
||||||
|
const tempUsers = getCurrentUsers()
|
||||||
|
if (tempUsers) tempUsers.users = validUsers.value ?? []
|
||||||
|
|
||||||
switch (lotteryOption.value.lotteryType) {
|
switch (lotteryOption.value.lotteryType) {
|
||||||
case 'single': {
|
case 'single': {
|
||||||
console.log('开始抽取单个用户')
|
console.log('开始抽取单个用户')
|
||||||
const removed = [] as number[]
|
|
||||||
removeSingleUser()
|
removeSingleUser()
|
||||||
function removeSingleUser() {
|
function removeSingleUser() {
|
||||||
if (data.users.length > lotteryOption.value.resultCount) {
|
if (data.users.length > lotteryOption.value.resultCount) {
|
||||||
@@ -186,7 +242,7 @@ function startLottery() {
|
|||||||
removeSingleUser()
|
removeSingleUser()
|
||||||
}, 500)
|
}, 500)
|
||||||
} else {
|
} else {
|
||||||
isLottering.value = false
|
onFinishLottery()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
@@ -198,68 +254,183 @@ function startLottery() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function onFinishLottery() {
|
||||||
|
resultUsers.value = JSON.parse(JSON.stringify(currentUsers.value?.users))
|
||||||
|
isLottering.value = false
|
||||||
|
isLotteried.value = true
|
||||||
|
notification.create({
|
||||||
|
title: '抽奖完成',
|
||||||
|
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)]))
|
||||||
|
),
|
||||||
|
meta: format(new Date(), 'yyyy-MM-dd HH:mm:ss'),
|
||||||
|
onAfterLeave: () => {
|
||||||
|
message.success('已保存至历史')
|
||||||
|
},
|
||||||
|
})
|
||||||
|
lotteryHistory.value.push({
|
||||||
|
users: currentUsers.value?.users ?? [],
|
||||||
|
time: Date.now(),
|
||||||
|
type: currentType.value,
|
||||||
|
url: inputDynamicId.value ? 'https://t.bilibili.com/' + inputDynamicId.value : inputDynamic.value ?? '',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
function reset() {
|
||||||
|
switch (currentType.value) {
|
||||||
|
case 'comment': {
|
||||||
|
commentUsers.value = JSON.parse(JSON.stringify(originCommentUsers.value))
|
||||||
|
console.log(originCommentUsers.value)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'forward': {
|
||||||
|
forwardUsers.value = JSON.parse(JSON.stringify(originForwardUsers.value))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isLotteried.value = false
|
||||||
|
}
|
||||||
|
function getLevelColor(level: number) {
|
||||||
|
switch (level) {
|
||||||
|
case 1: {
|
||||||
|
return 'gray'
|
||||||
|
}
|
||||||
|
case 2: {
|
||||||
|
return '#8bd29d'
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
return '#FEBB8B'
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
return '#7BCDEF'
|
||||||
|
}
|
||||||
|
case 5: {
|
||||||
|
return '#EE672A'
|
||||||
|
}
|
||||||
|
case 6: {
|
||||||
|
return '#F04C49'
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return 'gray'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NCard size="medium" embedded title="抽奖">
|
<NCard size="medium" embedded title="抽奖">
|
||||||
<NInput v-model:value="inputDynamic" placeholder="动态链接或直接输入动态Id" :status="inputDynamicId ? 'success' : 'warning'" />
|
<template #header-extra>
|
||||||
|
<NButton @click="showModal = true"> 历史记录 </NButton>
|
||||||
|
</template>
|
||||||
|
<NInput v-model:value="inputDynamic" placeholder="动态链接或直接输入动态Id" :status="inputDynamicId ? 'success' : 'warning'" :disabled="isLoading || isLottering" />
|
||||||
<NDivider style="margin: 10px 0 10px 0" />
|
<NDivider style="margin: 10px 0 10px 0" />
|
||||||
<NCard size="small" embedded title="选项">
|
<NCard size="small" embedded title="选项">
|
||||||
<template #header-extra>
|
<template #header-extra>
|
||||||
<NButton size="small" secondary @click="lotteryOption = defaultOption"> 恢复默认 </NButton>
|
<NButton size="small" secondary @click="lotteryOption = defaultOption"> 恢复默认 </NButton>
|
||||||
</template>
|
</template>
|
||||||
<NSpace justify="center">
|
<NSpace justify="center">
|
||||||
<NRadioGroup v-model:value="currentType" name="用户类型">
|
<NRadioGroup v-model:value="currentType" name="用户类型" :disabled="isLottering">
|
||||||
<NRadioButton value="comment"> 评论 </NRadioButton>
|
<NRadioButton value="comment"> 评论 </NRadioButton>
|
||||||
<NRadioButton value="forward"> 转发 </NRadioButton>
|
<NRadioButton value="forward"> 转发 </NRadioButton>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
|
<NDivider style="margin: 10px 0 10px 0"></NDivider>
|
||||||
<NSpace align="center">
|
<NSpace align="center">
|
||||||
<NInputGroup style="max-width: 200px">
|
<NInputGroup style="max-width: 200px">
|
||||||
<NInputGroupLabel> 抽选人数 </NInputGroupLabel>
|
<NInputGroupLabel> 抽选人数 </NInputGroupLabel>
|
||||||
<NInputNumber v-model:value="lotteryOption.resultCount" placeholder="" min="1" />
|
<NInputNumber v-model:value="lotteryOption.resultCount" placeholder="" min="1" />
|
||||||
</NInputGroup>
|
</NInputGroup>
|
||||||
<NCheckbox> 是否大会员 </NCheckbox>
|
<NCheckbox v-model:checked="lotteryOption.needVIP"> 需要大会员 </NCheckbox>
|
||||||
<NRadioGroup v-model:value="lotteryOption.lotteryType" name="抽取类型">
|
<template v-if="currentType == 'comment'">
|
||||||
|
<NCheckbox v-model:checked="lotteryOption.needCharge"> 需要充电 </NCheckbox>
|
||||||
|
<NCheckbox v-model:checked="lotteryOption.needFanCard"> 需要粉丝牌 </NCheckbox>
|
||||||
|
<NCollapseTransition>
|
||||||
|
<NInputGroup v-if="lotteryOption.needFanCard" style="max-width: 200px">
|
||||||
|
<NInputGroupLabel> 最低粉丝牌等级 </NInputGroupLabel>
|
||||||
|
<NInputNumber v-model:value="lotteryOption.fanCardLevel" min="1" max="50" :default-value="1" :disabled="isLottering" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NCollapseTransition>
|
||||||
|
</template>
|
||||||
|
<NRadioGroup v-model:value="lotteryOption.lotteryType" name="抽取类型" size="small" :disabled="isLottering">
|
||||||
<NRadioButton value="single"> 单个 </NRadioButton>
|
<NRadioButton value="single"> 单个 </NRadioButton>
|
||||||
<NRadioButton value="half"> 减半 </NRadioButton>
|
<NRadioButton value="half"> 减半 </NRadioButton>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</NCard>
|
</NCard>
|
||||||
<NDivider style="margin: 10px 0 10px 0" />
|
<br />
|
||||||
<NSpace justify="center" align="center">
|
<NSpace justify="center" align="center">
|
||||||
<NButton :disabled="!inputDynamicId || !isCommentCountDown || !token || isLottering" :loading="!token || isLoading" @click="onGet" type="primary"> 加载用户 </NButton>
|
<NButton :disabled="!inputDynamicId || !isCommentCountDown || !token || isLottering" :loading="!token || isLoading" @click="onGet" type="primary"> 加载用户 </NButton>
|
||||||
<NCountdown v-if="!isCommentCountDown" :duration="(currentUsers?.createTime ?? -1) + 60000 - Date.now()" @finish="isCommentCountDown = true" />
|
<NCountdown v-if="!isCommentCountDown" :duration="(currentUsers?.createTime ?? -1) + 60000 - Date.now()" @finish="isCommentCountDown = true" />
|
||||||
</NSpace>
|
</NSpace>
|
||||||
<NDivider style="margin: 10px 0 10px 0" />
|
<br />
|
||||||
<template v-if="currentUsers">
|
<NCard v-if="currentUsers" size="small">
|
||||||
<NSpace justify="space-between">
|
|
||||||
<span> 共 {{ currentUsers.users.length }} 人 </span>
|
|
||||||
</NSpace>
|
|
||||||
<NSpace justify="center">
|
<NSpace justify="center">
|
||||||
<NButton type="primary" @click="startLottery" secondary :loading="isLottering"> 开始抽取 </NButton>
|
<NButton type="primary" @click="startLottery" :loading="isLottering" :disabled="isLotteried"> 开始抽取 </NButton>
|
||||||
|
<NButton type="info" :disabled="isLottering || !isLotteried" @click="reset"> 重置 </NButton>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
<NDivider style="margin: 10px 0 10px 0" />
|
<NDivider style="margin: 10px 0 10px 0"> 共 {{ validUsers?.length }} 人</NDivider>
|
||||||
<NGrid cols="1 400:2 700:3 800:4" :x-gap="12" :y-gap="8">
|
<NGrid cols="1 500:2 800:3 1000:4" :x-gap="12" :y-gap="8">
|
||||||
<NGridItem v-for="item in currentUsers.users" v-bind:key="item.uId" :span="item.visiable ? 1 : 0">
|
<NGridItem v-for="item in validUsers" v-bind:key="item.uId">
|
||||||
<NCard size="small" :title="item.name">
|
<NCard size="small" :title="item.name" style="height: 155px">
|
||||||
<template #header>
|
<template #header>
|
||||||
<NSpace align="center">
|
<NSpace align="center" vertical :size="5">
|
||||||
<NAvatar round lazy :src="item.avatar + '@64w_64h'" :img-props="{ referrerpolicy: 'no-referrer' }" />
|
<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)" />
|
||||||
<NTag v-if="item.level" size="tiny">
|
<NSpace>
|
||||||
{{ item.level }}
|
<NTag v-if="item.isVIP" size="tiny" round :color="{ color: '#fb7299', textColor: 'white', borderColor: 'white' }"> 大会员 </NTag>
|
||||||
</NTag>
|
<NTooltip>
|
||||||
|
<template #trigger>
|
||||||
|
<NTag v-if="item.level" size="tiny" :color="{ color: getLevelColor(item.level), textColor: 'white', borderColor: 'white' }" :borderd="false"> LV {{ item.level }} </NTag>
|
||||||
|
</template>
|
||||||
|
用户等级
|
||||||
|
</NTooltip>
|
||||||
|
<NTag v-if="item.card" size="tiny" round>
|
||||||
|
<NTag size="tiny" round :bordered="false">
|
||||||
|
{{ item.card.level }}
|
||||||
|
</NTag>
|
||||||
|
<span style="color: #577fb8">
|
||||||
|
{{ item.card.name }}
|
||||||
|
</span>
|
||||||
|
</NTag>
|
||||||
|
</NSpace>
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
|
|
||||||
<NTag v-if="item.card" size="tiny">
|
|
||||||
{{ item.card.level }}
|
|
||||||
{{ item.card.name }}
|
|
||||||
</NTag>
|
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</template>
|
</template>
|
||||||
</NCard>
|
</NCard>
|
||||||
</NGridItem>
|
</NGridItem>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
</template>
|
</NCard>
|
||||||
</NCard>
|
</NCard>
|
||||||
|
<NModal v-model:show="showModal" preset="card" title="抽奖结果" style="max-width: 90%; width: 800px" closable>
|
||||||
|
<template #header-extra>
|
||||||
|
<NButton type="error" size="small" @click="lotteryHistory = []"> 清空 </NButton>
|
||||||
|
</template>
|
||||||
|
<NScrollbar v-if="lotteryHistory.length > 0" style="max-height: 80vh">
|
||||||
|
<NList>
|
||||||
|
<NListItem v-for="item in lotteryHistory" :key="item.time">
|
||||||
|
<NCard size="small">
|
||||||
|
<template #header>
|
||||||
|
<NTime :time="item.time" />
|
||||||
|
</template>
|
||||||
|
<template #header-extra>
|
||||||
|
<NButton type="error" size="small" @click="lotteryHistory.splice(lotteryHistory.indexOf(item), 1)"> 删除 </NButton>
|
||||||
|
</template>
|
||||||
|
<NSpace vertical>
|
||||||
|
<NSpace v-for="user in item.users" :key="user.uId">
|
||||||
|
<NAvatar round lazy :src="user.avatar + '@64w_64h'" :img-props="{ referrerpolicy: 'no-referrer' }" />
|
||||||
|
{{ user.name }}
|
||||||
|
</NSpace>
|
||||||
|
</NSpace>
|
||||||
|
<NDivider style="margin: 10px 0 10px 0" />
|
||||||
|
<NButton secondary @click="NavigateToNewTab(item.url)"> 目标动态 </NButton>
|
||||||
|
</NCard>
|
||||||
|
</NListItem>
|
||||||
|
</NList>
|
||||||
|
</NScrollbar>
|
||||||
|
<NEmpty v-else description="暂无记录" />
|
||||||
|
</NModal>
|
||||||
<VueTurnstile ref="turnstile" :site-key="TURNSTILE_KEY" v-model="token" theme="auto" style="text-align: center" />
|
<VueTurnstile ref="turnstile" :site-key="TURNSTILE_KEY" v-model="token" theme="auto" style="text-align: center" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ async function GetRecieveQAInfo() {
|
|||||||
if (data.data.length > 0) {
|
if (data.data.length > 0) {
|
||||||
recieveQuestions.value = new List(data.data)
|
recieveQuestions.value = new List(data.data)
|
||||||
.OrderBy((d) => d.isReaded)
|
.OrderBy((d) => d.isReaded)
|
||||||
|
//.ThenByDescending(d => d.isFavorite)
|
||||||
.ThenByDescending((d) => d.sendAt)
|
.ThenByDescending((d) => d.sendAt)
|
||||||
.ToArray()
|
.ToArray()
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,7 @@ async function read(question: QAInfo, read: boolean) {
|
|||||||
async function favorite(question: QAInfo, fav: boolean) {
|
async function favorite(question: QAInfo, fav: boolean) {
|
||||||
await QueryGetAPI(QUESTION_API_URL + 'favorite', {
|
await QueryGetAPI(QUESTION_API_URL + 'favorite', {
|
||||||
id: question.id,
|
id: question.id,
|
||||||
favorite: fav ? 'true' : 'false',
|
favorite: fav,
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
|
|||||||
6
src/views/manage/ScheduleManageView.vue
Normal file
6
src/views/manage/ScheduleManageView.vue
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
1
|
||||||
|
</template>
|
||||||
@@ -1,24 +1,28 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NAlert, NButton, NCard, NCheckbox, NDivider, NInput, NSpace, NTab, NTabPane, NTabs, NText, NUpload, UploadFileInfo, useMessage } from 'naive-ui'
|
import { NAlert, NButton, NCard, NCheckbox, NDivider, NInput, NSpace, NTab, NTabPane, NTabs, NText, NUpload, UploadFileInfo, useMessage } from 'naive-ui'
|
||||||
import GraphemeSplitter from 'grapheme-splitter'
|
import GraphemeSplitter from 'grapheme-splitter'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onUnmounted, ref } from 'vue'
|
||||||
import { useAccount } from '@/api/account'
|
import { useAccount } from '@/api/account'
|
||||||
import { useUser } from '@/api/user'
|
|
||||||
import { QAInfo, UserInfo } from '@/api/api-models'
|
import { QAInfo, UserInfo } from '@/api/api-models'
|
||||||
import { QueryPostAPI, QueryPostAPIWithParams } from '@/api/query'
|
import { QueryPostAPI } from '@/api/query'
|
||||||
import { QUESTION_API_URL, TURNSTILE_KEY } from '@/data/constants'
|
import { QUESTION_API_URL, TURNSTILE_KEY } from '@/data/constants'
|
||||||
import VueTurnstile from 'vue-turnstile'
|
import VueTurnstile from 'vue-turnstile'
|
||||||
|
|
||||||
|
const { biliInfo, userInfo } = defineProps<{
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
biliInfo: any | undefined
|
||||||
|
userInfo: UserInfo | undefined
|
||||||
|
}>()
|
||||||
|
|
||||||
const splitter = new GraphemeSplitter()
|
const splitter = new GraphemeSplitter()
|
||||||
|
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
const accountInfo = useAccount()
|
const accountInfo = useAccount()
|
||||||
const userInfo = ref<UserInfo>()
|
|
||||||
const token = ref('')
|
const token = ref('')
|
||||||
const turnstile = ref()
|
const turnstile = ref()
|
||||||
|
|
||||||
const isSelf = computed(() => {
|
const isSelf = computed(() => {
|
||||||
return userInfo.value?.id == accountInfo.value?.id
|
return userInfo?.id == accountInfo.value?.id
|
||||||
})
|
})
|
||||||
|
|
||||||
const questionMessage = ref('')
|
const questionMessage = ref('')
|
||||||
@@ -39,7 +43,7 @@ async function SendQuestion() {
|
|||||||
await QueryPostAPI<QAInfo>(
|
await QueryPostAPI<QAInfo>(
|
||||||
QUESTION_API_URL + 'send',
|
QUESTION_API_URL + 'send',
|
||||||
{
|
{
|
||||||
Target: userInfo.value?.id,
|
Target: userInfo?.id,
|
||||||
IsAnonymous: !accountInfo.value || isAnonymous.value,
|
IsAnonymous: !accountInfo.value || isAnonymous.value,
|
||||||
Message: questionMessage.value,
|
Message: questionMessage.value,
|
||||||
ImageBase64: fileList.value?.length > 0 ? await getBase64(fileList.value[0].file) : undefined,
|
ImageBase64: fileList.value?.length > 0 ? await getBase64(fileList.value[0].file) : undefined,
|
||||||
@@ -83,8 +87,8 @@ function OnFileListChange(files: UploadFileInfo[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onUnmounted(() => {
|
||||||
userInfo.value = await useUser()
|
turnstile.value?.remove()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
0
src/views/view/ScheduleView.vue
Normal file
0
src/views/view/ScheduleView.vue
Normal file
@@ -4,24 +4,23 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useUser } from '@/api/user'
|
|
||||||
import { SongListTypes, SongsInfo } from '@/api/api-models'
|
import { SongListTypes, SongsInfo } from '@/api/api-models'
|
||||||
import DefaultSongListTemplate from '@/views/view/songListTemplate/DefaultSongListTemplate.vue'
|
import DefaultSongListTemplate from '@/views/view/songListTemplate/DefaultSongListTemplate.vue'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { UserInfo } from '@/api/api-models'
|
import { UserInfo } from '@/api/api-models'
|
||||||
import { useRouteParams } from '@vueuse/router'
|
|
||||||
import { QueryGetAPI } from '@/api/query'
|
import { QueryGetAPI } from '@/api/query'
|
||||||
import { SONG_API_URL } from '@/data/constants'
|
import { SONG_API_URL } from '@/data/constants'
|
||||||
import { NSpin, useMessage } from 'naive-ui'
|
import { NSpin, useMessage } from 'naive-ui'
|
||||||
|
|
||||||
defineProps<{
|
const { biliInfo, userInfo } = defineProps<{
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
biliInfo: any | undefined
|
biliInfo: any | undefined
|
||||||
|
userInfo: UserInfo | undefined
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const songListType = computed(() => {
|
const songListType = computed(() => {
|
||||||
if (userInfo.value) {
|
if (userInfo) {
|
||||||
switch (userInfo.value.songListType) {
|
switch (userInfo.songListType) {
|
||||||
case SongListTypes.Default:
|
case SongListTypes.Default:
|
||||||
return DefaultSongListTemplate
|
return DefaultSongListTemplate
|
||||||
|
|
||||||
@@ -33,7 +32,6 @@ const songListType = computed(() => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
const songs = ref<SongsInfo[]>()
|
const songs = ref<SongsInfo[]>()
|
||||||
const uId = useRouteParams('id', '-1', { transform: Number })
|
|
||||||
const isLoading = ref(true)
|
const isLoading = ref(true)
|
||||||
const message = useMessage()
|
const message = useMessage()
|
||||||
|
|
||||||
@@ -42,7 +40,7 @@ const errMessage = ref('')
|
|||||||
async function getSongs() {
|
async function getSongs() {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
await QueryGetAPI<SongsInfo[]>(SONG_API_URL + 'get', {
|
await QueryGetAPI<SongsInfo[]>(SONG_API_URL + 'get', {
|
||||||
id: uId.value,
|
id: userInfo?.id,
|
||||||
})
|
})
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (data.code == 200) {
|
if (data.code == 200) {
|
||||||
@@ -61,10 +59,7 @@ async function getSongs() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const userInfo = ref<UserInfo>()
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
userInfo.value = await useUser()
|
|
||||||
await getSongs()
|
await getSongs()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -3,20 +3,20 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useUser } from '@/api/user'
|
|
||||||
import { IndexTypes } from '@/api/api-models'
|
import { IndexTypes } from '@/api/api-models'
|
||||||
import DefaultIndexTemplate from '@/views/view/indexTemplate/DefaultIndexTemplate.vue'
|
import DefaultIndexTemplate from '@/views/view/indexTemplate/DefaultIndexTemplate.vue'
|
||||||
import { computed, onMounted, ref } from 'vue'
|
import { computed, onMounted, ref } from 'vue'
|
||||||
import { UserInfo } from '@/api/api-models'
|
import { UserInfo } from '@/api/api-models'
|
||||||
|
|
||||||
defineProps<{
|
const { biliInfo, userInfo } = defineProps<{
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
biliInfo: any | undefined
|
biliInfo: any | undefined
|
||||||
|
userInfo: UserInfo | undefined
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const indexType = computed(() => {
|
const indexType = computed(() => {
|
||||||
if (userInfo.value) {
|
if (userInfo) {
|
||||||
switch (userInfo.value.indexType) {
|
switch (userInfo.indexType) {
|
||||||
case IndexTypes.Default:
|
case IndexTypes.Default:
|
||||||
return DefaultIndexTemplate
|
return DefaultIndexTemplate
|
||||||
|
|
||||||
@@ -27,9 +27,4 @@ const indexType = computed(() => {
|
|||||||
return DefaultIndexTemplate
|
return DefaultIndexTemplate
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const userInfo = ref<UserInfo>()
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
userInfo.value = await useUser()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function navigate(url: string) {
|
|||||||
<NDivider />
|
<NDivider />
|
||||||
<template v-if="userInfo?.biliId">
|
<template v-if="userInfo?.biliId">
|
||||||
<NSpace justify="center" align="center" vertical>
|
<NSpace justify="center" align="center" vertical>
|
||||||
<NAvatar :src="biliInfo?.face" :size="width > 750 ? 175 : 100" round bordered style="box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);" />
|
<NAvatar v-if="biliInfo" :src="biliInfo?.face" :size="width > 750 ? 175 : 100" round bordered style="box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2)" />
|
||||||
<NSpace align="baseline" justify="center">
|
<NSpace align="baseline" justify="center">
|
||||||
<NText strong style="font-size: 32px"> {{ biliInfo?.name }} </NText>
|
<NText strong style="font-size: 32px"> {{ biliInfo?.name }} </NText>
|
||||||
<NText strong style="font-size: 20px" depth="3"> ({{ userInfo?.name }}) </NText>
|
<NText strong style="font-size: 20px" depth="3"> ({{ userInfo?.name }}) </NText>
|
||||||
@@ -29,7 +29,7 @@ function navigate(url: string) {
|
|||||||
{{ biliInfo?.sign }}
|
{{ biliInfo?.sign }}
|
||||||
</NText>
|
</NText>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
<NDivider/>
|
<NDivider />
|
||||||
<NSpace align="center" justify="center">
|
<NSpace align="center" justify="center">
|
||||||
<NButton type="primary" @click="navigate('https://space.bilibili.com/' + userInfo?.biliId)"> 个人主页 </NButton>
|
<NButton type="primary" @click="navigate('https://space.bilibili.com/' + userInfo?.biliId)"> 个人主页 </NButton>
|
||||||
<NButton type="primary" secondary @click="navigate('https://live.bilibili.com/' + userInfo?.biliRoomId)"> 直播间 </NButton>
|
<NButton type="primary" secondary @click="navigate('https://live.bilibili.com/' + userInfo?.biliRoomId)"> 直播间 </NButton>
|
||||||
|
|||||||
@@ -6,13 +6,14 @@ import { NDivider } from 'naive-ui';
|
|||||||
|
|
||||||
const accountInfo = useAccount()
|
const accountInfo = useAccount()
|
||||||
|
|
||||||
const props = defineProps<{
|
defineProps<{
|
||||||
userInfo: UserInfo | undefined
|
userInfo: UserInfo | undefined
|
||||||
songs: SongsInfo[] | undefined
|
songs: SongsInfo[] | undefined
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SongList v-if="songs" :songs="songs ?? []" :is-self="accountInfo?.id.toString() == $route.params.id?.toString()"/>
|
<NDivider style="margin-top: 10px;"/>
|
||||||
|
<SongList v-if="songs" :songs="songs ?? []" :is-self="accountInfo?.id == userInfo?.id"/>
|
||||||
<NDivider/>
|
<NDivider/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
38
yarn.lock
38
yarn.lock
@@ -1092,6 +1092,14 @@ domutils@^3.0.1:
|
|||||||
domelementtype "^2.3.0"
|
domelementtype "^2.3.0"
|
||||||
domhandler "^5.0.3"
|
domhandler "^5.0.3"
|
||||||
|
|
||||||
|
echarts@^5.4.3:
|
||||||
|
version "5.4.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/echarts/-/echarts-5.4.3.tgz#f5522ef24419164903eedcfd2b506c6fc91fb20c"
|
||||||
|
integrity sha512-mYKxLxhzy6zyTi/FaEbJMOZU1ULGEQHaeIeuMR5L+JnJTpz+YR03mnnpBhbR4+UYJAgiXgpyTVLffPAjOTLkZA==
|
||||||
|
dependencies:
|
||||||
|
tslib "2.3.0"
|
||||||
|
zrender "5.4.4"
|
||||||
|
|
||||||
emoji-regex@^10.0.0:
|
emoji-regex@^10.0.0:
|
||||||
version "10.2.1"
|
version "10.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f"
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f"
|
||||||
@@ -2465,6 +2473,11 @@ regexp.prototype.flags@^1.5.1:
|
|||||||
define-properties "^1.2.0"
|
define-properties "^1.2.0"
|
||||||
set-function-name "^2.0.0"
|
set-function-name "^2.0.0"
|
||||||
|
|
||||||
|
resize-detector@^0.3.0:
|
||||||
|
version "0.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/resize-detector/-/resize-detector-0.3.0.tgz#fe495112e184695500a8f51e0389f15774cb1cfc"
|
||||||
|
integrity sha512-R/tCuvuOHQ8o2boRP6vgx8hXCCy87H1eY9V5imBYeVNyNVpuL9ciReSccLj2gDcax9+2weXy3bc8Vv+NRXeEvQ==
|
||||||
|
|
||||||
resolve-from@^4.0.0:
|
resolve-from@^4.0.0:
|
||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
|
||||||
@@ -2832,6 +2845,11 @@ tsconfig-paths@^3.14.2:
|
|||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
|
tslib@2.3.0:
|
||||||
|
version "2.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
|
||||||
|
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
|
||||||
|
|
||||||
tslib@^1.8.1:
|
tslib@^1.8.1:
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||||
@@ -2978,6 +2996,19 @@ vue-demi@>=0.14.5, vue-demi@latest:
|
|||||||
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92"
|
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.6.tgz#dc706582851dc1cdc17a0054f4fec2eb6df74c92"
|
||||||
integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
|
integrity sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==
|
||||||
|
|
||||||
|
vue-demi@^0.13.11:
|
||||||
|
version "0.13.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.11.tgz#7d90369bdae8974d87b1973564ad390182410d99"
|
||||||
|
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
|
||||||
|
|
||||||
|
vue-echarts@^6.6.1:
|
||||||
|
version "6.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/vue-echarts/-/vue-echarts-6.6.1.tgz#5b0398427ea98ba33175bdc80f34af4ce8f27ee4"
|
||||||
|
integrity sha512-EpreTzlNeJ+eaUn0AhXEmKJk98xJGecgTqAdyZovoXWnhTxnlW2HuBM0ei3y8rLw1JCUabf8/sYvxjlr8SzBKQ==
|
||||||
|
dependencies:
|
||||||
|
resize-detector "^0.3.0"
|
||||||
|
vue-demi "^0.13.11"
|
||||||
|
|
||||||
vue-eslint-parser@^8.0.0:
|
vue-eslint-parser@^8.0.0:
|
||||||
version "8.3.0"
|
version "8.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
|
resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz#5d31129a1b3dd89c0069ca0a1c88f970c360bd0d"
|
||||||
@@ -3148,3 +3179,10 @@ yocto-queue@^0.1.0:
|
|||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
|
zrender@5.4.4:
|
||||||
|
version "5.4.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/zrender/-/zrender-5.4.4.tgz#8854f1d95ecc82cf8912f5a11f86657cb8c9e261"
|
||||||
|
integrity sha512-0VxCNJ7AGOMCWeHVyTrGzUgrK4asT4ml9PEkeGirAkKNYXYzoPJCLvmyfdoOXcjTHPs10OZVMfD1Rwg16AZyYw==
|
||||||
|
dependencies:
|
||||||
|
tslib "2.3.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user