mirror of
https://github.com/Megghy/vtsuru.live.git
synced 2025-12-06 18:36:55 +08:00
update alert
This commit is contained in:
5
eslint.config.js
Normal file
5
eslint.config.js
Normal file
@@ -0,0 +1,5 @@
|
||||
// eslint.config.js
|
||||
import oxlint from 'eslint-plugin-oxlint'
|
||||
export default [
|
||||
oxlint, // oxlint should be the last one
|
||||
]
|
||||
@@ -18,6 +18,7 @@
|
||||
"easy-speech": "^2.2.0",
|
||||
"echarts": "^5.4.3",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-oxlint": "^0.2.0",
|
||||
"eslint-plugin-prettier": "^5.1.2",
|
||||
"fast-xml-parser": "^4.3.2",
|
||||
"file-saver": "^2.0.5",
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
<NLoadingBarProvider>
|
||||
<Suspense>
|
||||
<TempComponent>
|
||||
<NElement style="height: 100%" v-if="layout != 'obs'">
|
||||
<NLayoutContent style="height: 100%" v-if="layout != 'obs'">
|
||||
<ViewerLayout v-if="layout == 'viewer'" />
|
||||
<ManageLayout v-else-if="layout == 'manage'" />
|
||||
<OpenLiveLayout v-else-if="layout == 'open-live'" />
|
||||
<template v-else-if="layout == ''">
|
||||
<RouterView />
|
||||
</template>
|
||||
</NElement>
|
||||
</NLayoutContent>
|
||||
<RouterView v-else />
|
||||
</TempComponent>
|
||||
<template #fallback>
|
||||
@@ -30,7 +30,7 @@ import { useProviderStore } from '@/store/useProviderStore'
|
||||
import ManageLayout from '@/views/ManageLayout.vue'
|
||||
import ViewerLayout from '@/views/ViewerLayout.vue'
|
||||
import { useStorage } from '@vueuse/core'
|
||||
import { NConfigProvider, NElement, NLoadingBarProvider, NMessageProvider, NNotificationProvider, NSpin, darkTheme, dateZhCN, useLoadingBar, useOsTheme, zhCN } from 'naive-ui'
|
||||
import { NConfigProvider, NElement, NLayoutContent, NLoadingBarProvider, NMessageProvider, NNotificationProvider, NSpin, darkTheme, dateZhCN, useLoadingBar, useOsTheme, zhCN } from 'naive-ui'
|
||||
import { computed, defineComponent, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { ThemeType } from './api/api-models'
|
||||
|
||||
@@ -497,4 +497,5 @@ export enum FeedbackStatus {
|
||||
Finish,
|
||||
Todo,
|
||||
Reject,
|
||||
Developing,
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ const status = computed(() => {
|
||||
这是一个可以持续监听直播间内的 Superchat 和上舰事件并上传到本站进行记录的 Nodejs/.Net 程序
|
||||
<br />
|
||||
事件上传到本站后允许按照自定义范围进行查询, 并导出为 CSV 之类的表格
|
||||
<br />
|
||||
<NButton type="info" size="small" tag="a" href="https://www.yuque.com/megghy/dez70g/vfvcyv3024xvaa1p" target="_blank"> 关于 EVENT-FETCHER </NButton>
|
||||
</NTooltip>
|
||||
</template>
|
||||
<NTag :type="status">
|
||||
|
||||
59
src/components/FeedbackItem.vue
Normal file
59
src/components/FeedbackItem.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<script setup lang="ts">
|
||||
import { FeedbackStatus, FeedbackType, ResponseFeedbackModel } from '@/api/api-models'
|
||||
import { NCard, NTag, NEllipsis, NDivider, NSpin, NText, NSpace, NTooltip, NTime } from 'naive-ui'
|
||||
import { computed } from 'vue'
|
||||
|
||||
defineProps<{
|
||||
item: ResponseFeedbackModel
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NCard v-bind:key="item.createAt" size="small" embedded style="min-width: 300px; max-width: 500px">
|
||||
<template #header>
|
||||
<NTag v-if="item.status == FeedbackStatus.Padding" :bordered="false"> 等待 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Progressing" type="success">
|
||||
<template #icon>
|
||||
<NSpin :size="12" />
|
||||
</template>
|
||||
处理中
|
||||
</NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Finish" :bordered="false" type="primary"> 已完成 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Todo" :bordered="false" type="info"> 计划中 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Reject" :bordered="false" type="error"> 搁置 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Developing" type="warning"> 开发中 </NTag>
|
||||
<NDivider vertical />
|
||||
<NTag v-if="!item.userName"> 匿名 </NTag>
|
||||
<template v-else>
|
||||
<NEllipsis>
|
||||
{{ item.userName }}
|
||||
</NEllipsis>
|
||||
</template>
|
||||
<NDivider vertical />
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText depth="3" style="font-size: small">
|
||||
<NTime :time="item.createAt" type="relative" />
|
||||
</NText>
|
||||
</template>
|
||||
<NTime :time="item.createAt" />
|
||||
</NTooltip>
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NTag v-if="item.type == FeedbackType.Opinion" :bordered="false" size="small" type="info" :color="{ color: '#5f877d', textColor: 'white' }"> 建议 </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.Bug" :bordered="false" size="small" type="info" :color="{ color: '#875f5f', textColor: 'white' }"> Bug </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.FunctionRequest" :bordered="false" size="small" type="info" :color="{ color: '#5f6887', textColor: 'white' }"> 功能 </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.Other" :bordered="false" size="small" type="info" :color="{ color: '#595557', textColor: 'white' }"> 其他 </NTag>
|
||||
</template>
|
||||
{{ item.message }}
|
||||
<template v-if="item.replyMessage" #footer>
|
||||
<NDivider style="margin: 0px 0 10px 0" />
|
||||
<NSpace align="center">
|
||||
<div :style="`border-radius: 4px; background-color: #75c37f; width: 10px; height: 15px`"></div>
|
||||
<NText>
|
||||
{{ item.replyMessage }}
|
||||
</NText>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NCard>
|
||||
</template>
|
||||
@@ -1,6 +1,10 @@
|
||||
import { useProviderStore } from '@/store/useProviderStore'
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
|
||||
import IndexView from '../views/IndexView.vue'
|
||||
import manage from './manage'
|
||||
import user from './user'
|
||||
import obs from './obs'
|
||||
import open_live from './open_live'
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
{
|
||||
@@ -54,294 +58,18 @@ const routes: Array<RouteRecordRaw> = [
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/user/:id',
|
||||
name: 'user',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'user-index',
|
||||
component: () => import('@/views/view/UserIndexView.vue'),
|
||||
meta: {
|
||||
title: '主页',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-list',
|
||||
name: 'user-songList',
|
||||
component: () => import('@/views/view/SongListView.vue'),
|
||||
meta: {
|
||||
title: '歌单',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'question-box',
|
||||
name: 'user-questionBox',
|
||||
component: () => import('@/views/view/QuestionBoxView.vue'),
|
||||
meta: {
|
||||
title: '提问箱',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
name: 'user-schedule',
|
||||
component: () => import('@/views/view/ScheduleView.vue'),
|
||||
meta: {
|
||||
title: '日程',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
//管理页面
|
||||
{
|
||||
path: '/manage',
|
||||
name: 'manage',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'manage-index',
|
||||
component: () => import('@/views/manage/DashboardView.vue'),
|
||||
meta: {
|
||||
title: '面板',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-list',
|
||||
name: 'manage-songList',
|
||||
component: () => import('@/views/manage/SongListManageView.vue'),
|
||||
meta: {
|
||||
title: '歌单',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'question-box',
|
||||
name: 'manage-questionBox',
|
||||
component: () => import('@/views/manage/QuestionBoxManageView.vue'),
|
||||
meta: {
|
||||
title: '提问箱',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'lottery',
|
||||
name: 'manage-lottery',
|
||||
component: () => import('@/views/manage/LotteryView.vue'),
|
||||
meta: {
|
||||
title: '动态抽奖',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
name: 'manage-history',
|
||||
component: () => import('@/views/manage/HistoryView.vue'),
|
||||
meta: {
|
||||
title: '数据跟踪',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
name: 'manage-schedule',
|
||||
component: () => import('@/views/manage/ScheduleManageView.vue'),
|
||||
meta: {
|
||||
title: '日程',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'event',
|
||||
name: 'manage-event',
|
||||
component: () => import('@/views/manage/EventView.vue'),
|
||||
meta: {
|
||||
title: '事件记录',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'video-collect',
|
||||
name: 'manage-videoCollect',
|
||||
component: () => import('@/views/manage/VideoCollectManageView.vue'),
|
||||
meta: {
|
||||
title: '视频征集',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'video-collect/:id',
|
||||
name: 'manage-videoCollect-Detail',
|
||||
component: () => import('@/views/manage/VideoCollectDetailView.vue'),
|
||||
meta: {
|
||||
title: '详情 · 视频征集',
|
||||
keepAlive: true,
|
||||
parent: 'manage-videoCollect',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live-lottery',
|
||||
name: 'manage-liveLottery',
|
||||
component: () => import('@/views/open_live/OpenLottery.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'manage-liveQueue',
|
||||
component: () => import('@/views/open_live/OpenQueue.vue'),
|
||||
meta: {
|
||||
title: '排队',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'speech',
|
||||
name: 'manage-speech',
|
||||
component: () => import('@/views/open_live/ReadDanmaku.vue'),
|
||||
meta: {
|
||||
title: '读弹幕',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'manage-songRequest',
|
||||
component: () => import('@/views/open_live/SongRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌 (歌势',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'music-request',
|
||||
name: 'manage-musicRequest',
|
||||
component: () => import('@/views/open_live/MusicRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌 (点播',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live',
|
||||
name: 'manage-live',
|
||||
component: () => import('@/views/manage/LiveManager.vue'),
|
||||
meta: {
|
||||
title: '直播记录',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live/:id',
|
||||
name: 'manage-liveDetail',
|
||||
component: () => import('@/views/manage/LiveDetailManage.vue'),
|
||||
meta: {
|
||||
title: '直播详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'feedback',
|
||||
name: 'manage-feedback',
|
||||
component: () => import('@/views/FeedbackManage.vue'),
|
||||
path: '/feedback',
|
||||
name: 'feedback',
|
||||
component: () => import('@/views/ViewerFeedbackView.vue'),
|
||||
meta: {
|
||||
title: '反馈',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/open-live',
|
||||
name: 'open-live',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'open-live-index',
|
||||
component: () => import('@/views/open_live/OpenLiveIndex.vue'),
|
||||
meta: {
|
||||
title: '开放平台',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'lottery',
|
||||
name: 'open-live-lottery',
|
||||
component: () => import('@/views/open_live/OpenLottery.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'open-live-song-request',
|
||||
component: () => import('@/views/open_live/SongRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'open-live-queue',
|
||||
component: () => import('@/views/open_live/OpenQueue.vue'),
|
||||
meta: {
|
||||
title: '排队',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'speech',
|
||||
name: 'open-live-speech',
|
||||
component: () => import('@/views/open_live/ReadDanmaku.vue'),
|
||||
meta: {
|
||||
title: '读弹幕',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/obs',
|
||||
name: 'obs',
|
||||
children: [
|
||||
{
|
||||
path: 'live-lottery',
|
||||
name: 'obs-live-lottery',
|
||||
component: () => import('@/views/obs/LiveLotteryOBS.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'obs-song-request',
|
||||
component: () => import('@/views/obs/SongRequestOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕点歌 (歌势',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'obs-queue',
|
||||
component: () => import('@/views/obs/QueueOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕排队',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'music-request',
|
||||
name: 'obs-music-request',
|
||||
component: () => import('@/views/obs/MusicRequestOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕排队 (播放',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
manage,
|
||||
user,
|
||||
obs,
|
||||
open_live,
|
||||
{
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: 'notfound',
|
||||
|
||||
163
src/router/manage.ts
Normal file
163
src/router/manage.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
export default //管理页面
|
||||
{
|
||||
path: '/manage',
|
||||
name: 'manage',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'manage-index',
|
||||
component: () => import('@/views/manage/DashboardView.vue'),
|
||||
meta: {
|
||||
title: '面板',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-list',
|
||||
name: 'manage-songList',
|
||||
component: () => import('@/views/manage/SongListManageView.vue'),
|
||||
meta: {
|
||||
title: '歌单',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'question-box',
|
||||
name: 'manage-questionBox',
|
||||
component: () => import('@/views/manage/QuestionBoxManageView.vue'),
|
||||
meta: {
|
||||
title: '提问箱',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'lottery',
|
||||
name: 'manage-lottery',
|
||||
component: () => import('@/views/manage/LotteryView.vue'),
|
||||
meta: {
|
||||
title: '动态抽奖',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'history',
|
||||
name: 'manage-history',
|
||||
component: () => import('@/views/manage/HistoryView.vue'),
|
||||
meta: {
|
||||
title: '数据跟踪',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
name: 'manage-schedule',
|
||||
component: () => import('@/views/manage/ScheduleManageView.vue'),
|
||||
meta: {
|
||||
title: '日程',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'event',
|
||||
name: 'manage-event',
|
||||
component: () => import('@/views/manage/EventView.vue'),
|
||||
meta: {
|
||||
title: '事件记录',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'video-collect',
|
||||
name: 'manage-videoCollect',
|
||||
component: () => import('@/views/manage/VideoCollectManageView.vue'),
|
||||
meta: {
|
||||
title: '视频征集',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'video-collect/:id',
|
||||
name: 'manage-videoCollect-Detail',
|
||||
component: () => import('@/views/manage/VideoCollectDetailView.vue'),
|
||||
meta: {
|
||||
title: '详情 · 视频征集',
|
||||
keepAlive: true,
|
||||
parent: 'manage-videoCollect',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live-lottery',
|
||||
name: 'manage-liveLottery',
|
||||
component: () => import('@/views/open_live/OpenLottery.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'manage-liveQueue',
|
||||
component: () => import('@/views/open_live/OpenQueue.vue'),
|
||||
meta: {
|
||||
title: '排队',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'speech',
|
||||
name: 'manage-speech',
|
||||
component: () => import('@/views/open_live/ReadDanmaku.vue'),
|
||||
meta: {
|
||||
title: '读弹幕',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'manage-songRequest',
|
||||
component: () => import('@/views/open_live/SongRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌 (歌势',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'music-request',
|
||||
name: 'manage-musicRequest',
|
||||
component: () => import('@/views/open_live/MusicRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌 (点播',
|
||||
keepAlive: true,
|
||||
danmaku: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live',
|
||||
name: 'manage-live',
|
||||
component: () => import('@/views/manage/LiveManager.vue'),
|
||||
meta: {
|
||||
title: '直播记录',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'live/:id',
|
||||
name: 'manage-liveDetail',
|
||||
component: () => import('@/views/manage/LiveDetailManage.vue'),
|
||||
meta: {
|
||||
title: '直播详情',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'feedback',
|
||||
name: 'manage-feedback',
|
||||
component: () => import('@/views/FeedbackManage.vue'),
|
||||
meta: {
|
||||
title: '反馈',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
38
src/router/obs.ts
Normal file
38
src/router/obs.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
export default {
|
||||
path: '/obs',
|
||||
name: 'obs',
|
||||
children: [
|
||||
{
|
||||
path: 'live-lottery',
|
||||
name: 'obs-live-lottery',
|
||||
component: () => import('@/views/obs/LiveLotteryOBS.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'obs-song-request',
|
||||
component: () => import('@/views/obs/SongRequestOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕点歌 (歌势',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'obs-queue',
|
||||
component: () => import('@/views/obs/QueueOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕排队',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'music-request',
|
||||
name: 'obs-music-request',
|
||||
component: () => import('@/views/obs/MusicRequestOBS.vue'),
|
||||
meta: {
|
||||
title: '弹幕排队 (播放',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
46
src/router/open_live.ts
Normal file
46
src/router/open_live.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
export default {
|
||||
path: '/open-live',
|
||||
name: 'open-live',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'open-live-index',
|
||||
component: () => import('@/views/open_live/OpenLiveIndex.vue'),
|
||||
meta: {
|
||||
title: '开放平台',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'lottery',
|
||||
name: 'open-live-lottery',
|
||||
component: () => import('@/views/open_live/OpenLottery.vue'),
|
||||
meta: {
|
||||
title: '直播抽奖',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-request',
|
||||
name: 'open-live-song-request',
|
||||
component: () => import('@/views/open_live/SongRequest.vue'),
|
||||
meta: {
|
||||
title: '点歌',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'queue',
|
||||
name: 'open-live-queue',
|
||||
component: () => import('@/views/open_live/OpenQueue.vue'),
|
||||
meta: {
|
||||
title: '排队',
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'speech',
|
||||
name: 'open-live-speech',
|
||||
component: () => import('@/views/open_live/ReadDanmaku.vue'),
|
||||
meta: {
|
||||
title: '读弹幕',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
42
src/router/user.ts
Normal file
42
src/router/user.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export default {
|
||||
path: '/user/:id',
|
||||
name: 'user',
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: 'user-index',
|
||||
component: () => import('@/views/view/UserIndexView.vue'),
|
||||
meta: {
|
||||
title: '主页',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'song-list',
|
||||
name: 'user-songList',
|
||||
component: () => import('@/views/view/SongListView.vue'),
|
||||
meta: {
|
||||
title: '歌单',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'question-box',
|
||||
name: 'user-questionBox',
|
||||
component: () => import('@/views/view/QuestionBoxView.vue'),
|
||||
meta: {
|
||||
title: '提问箱',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: 'schedule',
|
||||
name: 'user-schedule',
|
||||
component: () => import('@/views/view/ScheduleView.vue'),
|
||||
meta: {
|
||||
title: '日程',
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
import { useAccount } from '@/api/account'
|
||||
import { FeedbackStatus, FeedbackType, ResponseFeedbackModel } from '@/api/api-models'
|
||||
import { QueryGetAPI, QueryPostAPI } from '@/api/query'
|
||||
import FeedbackItem from '@/components/FeedbackItem.vue'
|
||||
import { FEEDBACK_API_URL } from '@/data/constants'
|
||||
import { List } from 'linqts'
|
||||
import { NButton, NCard, NCheckbox, NDivider, NEllipsis, NEmpty, NInput, NModal, NRadioButton, NRadioGroup, NSpace, NSpin, NTag, NText, NTime, NTooltip, useMessage } from 'naive-ui'
|
||||
@@ -24,6 +25,7 @@ const order = {
|
||||
[FeedbackStatus.Todo]: 3,
|
||||
[FeedbackStatus.Finish]: 4,
|
||||
[FeedbackStatus.Reject]: 5,
|
||||
[FeedbackStatus.Developing]: 6,
|
||||
}
|
||||
const selectedFeedback = computed(() => {
|
||||
return feedbacks.value.sort((a, b) => {
|
||||
@@ -79,7 +81,12 @@ async function add() {
|
||||
|
||||
<template>
|
||||
<NSpace align="center">
|
||||
<NButton @click="showAddModal = true" type="info">添加反馈</NButton>
|
||||
<NTooltip :disabled="accountInfo !== undefined">
|
||||
<template #trigger>
|
||||
<NButton @click="showAddModal = true" type="info" :disabled="!accountInfo">添加反馈</NButton>
|
||||
</template>
|
||||
你需要登陆后才能提交反馈
|
||||
</NTooltip>
|
||||
<NText depth="3"> 或者直接加群 873260337 说也可以 </NText>
|
||||
</NSpace>
|
||||
<NDivider>
|
||||
@@ -94,54 +101,41 @@ async function add() {
|
||||
</NTooltip>
|
||||
</NDivider>
|
||||
<NEmpty v-if="feedbacks.length == 0" description="暂无反馈" />
|
||||
<NSpace v-else>
|
||||
<NCard v-for="item in selectedFeedback" v-bind:key="item.createAt" size="small" embedded style="min-width: 300px">
|
||||
<template #header>
|
||||
<NTag v-if="item.status == FeedbackStatus.Padding" :bordered="false"> 等待 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Progressing" type="success">
|
||||
<template #icon>
|
||||
<NSpin :size="12" />
|
||||
</template>
|
||||
处理中
|
||||
</NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Finish" :bordered="false" type="primary"> 已完成 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Todo" :bordered="false" type="info"> 计划中 </NTag>
|
||||
<NTag v-else-if="item.status == FeedbackStatus.Reject" :bordered="false" type="warning"> 搁置 </NTag>
|
||||
<NDivider vertical />
|
||||
<NTag v-if="!item.userName"> 匿名 </NTag>
|
||||
<NSpace v-else-if="orderType == 'time'">
|
||||
<FeedbackItem v-for="item in selectedFeedback" :item="item" />
|
||||
</NSpace>
|
||||
<template v-else>
|
||||
<NEllipsis>
|
||||
{{ item.userName }}
|
||||
</NEllipsis>
|
||||
</template>
|
||||
<NDivider vertical />
|
||||
<NTooltip>
|
||||
<template #trigger>
|
||||
<NText depth="3" style="font-size: small">
|
||||
<NTime :time="item.createAt" type="relative" />
|
||||
</NText>
|
||||
</template>
|
||||
<NTime :time="item.createAt" />
|
||||
</NTooltip>
|
||||
</template>
|
||||
<template #header-extra>
|
||||
<NTag v-if="item.type == FeedbackType.Opinion" :bordered="false" size="small" type="info" :color="{ color: '#5f877d', textColor: 'white' }"> 建议 </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.Bug" :bordered="false" size="small" type="info" :color="{ color: '#875f5f', textColor: 'white' }"> Bug </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.FunctionRequest" :bordered="false" size="small" type="info" :color="{ color: '#5f6887', textColor: 'white' }"> 功能 </NTag>
|
||||
<NTag v-else-if="item.type == FeedbackType.Other" :bordered="false" size="small" type="info" :color="{ color: '#595557', textColor: 'white' }"> 其他 </NTag>
|
||||
</template>
|
||||
{{ item.message }}
|
||||
<template v-if="item.replyMessage" #footer>
|
||||
<NDivider style="margin: 0px 0 10px 0" />
|
||||
<NSpace align="center">
|
||||
<div :style="`border-radius: 4px; background-color: #75c37f; width: 10px; height: 15px`"></div>
|
||||
<NText>
|
||||
{{ item.replyMessage }}
|
||||
</NText>
|
||||
<NDivider> 开发计划 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Developing).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Developing)" :item="item" />
|
||||
</NSpace>
|
||||
<NDivider> 处理中 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Progressing).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Progressing)" :item="item" />
|
||||
</NSpace>
|
||||
<NDivider> 等待回复 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Padding).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Padding)" :item="item" />
|
||||
</NSpace>
|
||||
<NDivider> 计划中 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Todo).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Todo)" :item="item" />
|
||||
</NSpace>
|
||||
<NDivider> 已完成 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Finish).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Finish)" :item="item" />
|
||||
</NSpace>
|
||||
<NDivider> 搁置 </NDivider>
|
||||
<NEmpty v-if="selectedFeedback.filter((f) => f.status == FeedbackStatus.Reject).length == 0" description="无" />
|
||||
<NSpace v-else>
|
||||
<FeedbackItem v-for="item in selectedFeedback.filter((f) => f.status == FeedbackStatus.Reject)" :item="item" />
|
||||
</NSpace>
|
||||
</template>
|
||||
</NCard>
|
||||
</NSpace>
|
||||
<NModal v-model:show="showAddModal" preset="card" title="添加反馈" style="width: 600px; max-width: 90vw">
|
||||
<NSpace vertical>
|
||||
<NInput v-model:value="newFeedback.message" type="textarea" placeholder="请输入反馈内容" clearable show-count maxlength="1000" />
|
||||
|
||||
9
src/views/ViewerFeedbackView.vue
Normal file
9
src/views/ViewerFeedbackView.vue
Normal file
@@ -0,0 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { NLayoutContent } from 'naive-ui'
|
||||
import FeedbackManage from './FeedbackManage.vue'
|
||||
</script>
|
||||
<template>
|
||||
<div style="margin: 16px;">
|
||||
<FeedbackManage />
|
||||
</div>
|
||||
</template>
|
||||
@@ -190,10 +190,13 @@ onMounted(async () => {
|
||||
</div>
|
||||
</Transition>
|
||||
<NMenu :default-value="$route.name?.toString()" :collapsed-width="64" :collapsed-icon-size="22" :options="menuOptions" />
|
||||
<NSpace justify="center">
|
||||
<NText depth="3" v-if="width > 150">
|
||||
<NSpace v-if="width > 150" justify="center" align="center" vertical>
|
||||
<NText depth="3">
|
||||
有更多功能建议请
|
||||
<NButton text type="info" @click="$router.push({ name: 'about' })"> 反馈 </NButton>
|
||||
<NButton text type="info" tag="a" href="/feedback" target="_blank"> 反馈 </NButton>
|
||||
</NText>
|
||||
<NText depth="3">
|
||||
<NButton text type="info" tag="a" href="/about" target="_blank"> 关于本站 </NButton>
|
||||
</NText>
|
||||
</NSpace>
|
||||
</NLayoutSider>
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
import { useAccount } from '@/api/account'
|
||||
import { QueryGetAPI } from '@/api/query'
|
||||
import { HISTORY_API_URL } from '@/data/constants'
|
||||
import { Info24Filled } from '@vicons/fluent'
|
||||
import { addHours, format, isSameDay, isSameHour, startOfHour } from 'date-fns'
|
||||
import { BarChart, LineChart } from 'echarts/charts'
|
||||
import { DataZoomComponent, GridComponent, LegendComponent, TitleComponent, ToolboxComponent, TooltipComponent } from 'echarts/components'
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { NAlert, NCard, NSpace, NSpin, useMessage } from 'naive-ui'
|
||||
import { NAlert, NButton, NCard, NIcon, NSpace, NSpin, NText, NTooltip, useMessage } from 'naive-ui'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import VChart from 'vue-echarts'
|
||||
|
||||
@@ -486,6 +487,24 @@ onMounted(async () => {
|
||||
<NAlert v-if="accountInfo?.isBiliVerified != true" type="info"> 尚未进行Bilibili认证 </NAlert>
|
||||
<NSpin v-else-if="isLoading" show />
|
||||
<NCard v-else size="small">
|
||||
<NTooltip trigger="click" placement="bottom">
|
||||
<template #trigger>
|
||||
<NButton type="info">
|
||||
<template #icon>
|
||||
<NIcon :component="Info24Filled" />
|
||||
</template>
|
||||
关于数据更新
|
||||
</NButton>
|
||||
</template>
|
||||
更新速度:
|
||||
<NSpace vertical>
|
||||
<span> 粉丝数: 1000粉以下: 每24小时一次, 1000-10000粉: 每6小时一次, 10000粉以上: 每小时一次 </span>
|
||||
<span> 舰长数: 10舰以下: 每24小时一次, 10-50舰: 每12小时一次, 50舰以上: 每6小时一次 </span>
|
||||
<span> 投稿数据: 每天一次 </span>
|
||||
</NSpace>
|
||||
</NTooltip>
|
||||
<br />
|
||||
<br />
|
||||
<NSpace vertical>
|
||||
<VChart :option="fansOption" style="height: 200px" />
|
||||
<VChart :option="guardsOption" style="height: 200px" />
|
||||
|
||||
@@ -46,7 +46,7 @@ async function get() {
|
||||
return data.data
|
||||
}
|
||||
} catch (err) {}
|
||||
return {} as { playing: WaitMusicInfo; waiting: WaitMusicInfo[] }
|
||||
return originSongs.value
|
||||
}
|
||||
const isMoreThanContainer = computed(() => {
|
||||
return originSongs.value.waiting.length * itemHeight > height.value
|
||||
@@ -95,9 +95,6 @@ onUnmounted(() => {
|
||||
{{ item.music.name }}
|
||||
</div>
|
||||
<p class="music-request-list-item-name">{{ item.from ? item.from.name : '主播添加' }}</p>
|
||||
<div class="music-request-list-item-level" :has-level="(item.from?.fans_medal_level ?? 0) > 0">
|
||||
{{ `${item.from?.fans_medal_name} ${item.from?.fans_medal_level}` }}
|
||||
</div>
|
||||
</span>
|
||||
</Vue3Marquee>
|
||||
</template>
|
||||
|
||||
@@ -2363,6 +2363,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-oxlint@npm:^0.2.0":
|
||||
version: 0.2.0
|
||||
resolution: "eslint-plugin-oxlint@npm:0.2.0"
|
||||
checksum: fc0d6b56e9e93129b16f46f5ddfd2bf7233292b6a643efeda4c421d2796ee009333ca3bada4241b14dcd14b21eb757ead4aaa84671af73da925042eabed425d8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"eslint-plugin-prettier@npm:^5.1.2":
|
||||
version: 5.1.2
|
||||
resolution: "eslint-plugin-prettier@npm:5.1.2"
|
||||
@@ -4873,6 +4880,7 @@ __metadata:
|
||||
eslint: "npm:^8.56.0"
|
||||
eslint-config-prettier: "npm:^9.1.0"
|
||||
eslint-plugin-import: "npm:^2.29.1"
|
||||
eslint-plugin-oxlint: "npm:^0.2.0"
|
||||
eslint-plugin-prettier: "npm:^5.1.2"
|
||||
eslint-plugin-vue: "npm:^9.19.2"
|
||||
fast-xml-parser: "npm:^4.3.2"
|
||||
|
||||
Reference in New Issue
Block a user