LoongPanel-Asp/web/layouts/Main.vue

327 lines
8.5 KiB
Vue
Executable File

<script lang="ts" setup>
import SideBar from "~/components/shell/SideBar.vue";
import TitleBar from "~/components/shell/TitleBar.vue";
import FloaterBar from "~/components/shell/FloaterBar.vue";
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
import type {UserInfoType} from "~/types/UserType";
import type {HttpType} from "~/types/baseType";
import {useSessionSignalRStore} from "~/strores/HubStore";
import {POSITION, useToast} from "vue-toastification";
import {type dataHistoryType, useDataStore} from "~/strores/DataStore";
import VueDragResize from 'vue-drag-resize'
const audio = ref<any>(null);
const audio1 = ref<any>(null);
const audio2 = ref<any>(null);
const toast = useToast()
const visible = ref<boolean>(false)
const DataStore = useDataStore()
const {$gsap} = useNuxtApp()
const mainRef = ref<HTMLElement>()
const mainLayoutStore = useMainLayoutStore()
const ServerList = ref<{ label: string, value: string }[]>([])
const {isScrolling} = useScroll(mainRef)
watch(isScrolling, (newValue) => {
mainLayoutStore.IsScrolling = newValue
})
onMounted(() => {
$fetch('/Api/User/Info', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + useCookie('token').value
},
baseURL: useRuntimeConfig().public.baseUrl
}).then(res => {
const data = res as HttpType<UserInfoType>
if (data.code === 200) {
mainLayoutStore.UserInfo = data.data
}
})
})
//获取服务器列表
onMounted(() => {
$fetch('/Api/Server/GetServerList', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + useCookie('token').value
},
baseURL: useRuntimeConfig().public.baseUrl
}).then(res => {
const data = res as { name: string, id: string }[]
ServerList.value = data.map(item => ({label: item.name, value: item.id}))
if (!mainLayoutStore.SelectServer.value) {
mainLayoutStore.SelectServer = ServerList.value[0];
}
})
})
const signalR = useSessionSignalRStore();
//有且运行一次
onMounted(() => {
signalR.initConnection();
signalR.connection?.on('userJoined', (data: any) => {
mainLayoutStore.setOnlineUsers(data)
})
signalR.connection?.on('userLeft', (data: any) => {
const uses = mainLayoutStore.OnlineUsers.filter(item => item.id !== data)
mainLayoutStore.setOnlineUsers(uses)
})
signalR.connection?.on('ReceiveData', (id: string, type: string, message: string) => {
if (id !== mainLayoutStore.SelectServer.value) return
DataStore.setData(type, message)
})
signalR.connection?.on('ReceiveWaring', (value: string,valueName) => {
// //两位小数
audio2.value.currentTime = 0;
audio2.value && audio2.value.click()
audio2.value && audio2.value.play()
toast.error(`你设定的${valueName}已经达到警告阈值,当前值为 ${value}`,{
position: POSITION.BOTTOM_RIGHT,
timeout:5000,
})
})
signalR.connection?.on('ReceiveNotify', (value: string,valueName) => {
//两位小数
audio1.value.currentTime = 0;
const {
isSupported,
show,
} = useWebNotification({
title: `你设定的${valueName}已经达到通知阈值,当前值为 ${value}`,
dir: 'auto',
lang: 'en',
renotify: true,
tag: '通知',
})
if(isSupported.value){
Notification.requestPermission().then(res => {
console.log(res)
})
show()
}
audio1.value && audio1.value.click()
audio1.value && audio1.value.play()
toast.info(`你设定的${valueName}已经达到通知阈值,当前值为 ${value}`,{
position: POSITION.BOTTOM_RIGHT,
timeout:5000,
})
})
signalR.connection?.on("sendMessage", (id, message) => {
audio.value.currentTime = 0;
audio.value && audio.value.click()
audio.value && audio.value.play()
const user = mainLayoutStore.OnlineUsers.find(user => user.id === id)
toast.info(`${user?.nickName}向你发送了一条消息`, {
position: POSITION.BOTTOM_RIGHT,
})
console.log(`${user?.nickName}对你说: ${message}`)
setTimeout(() => {
audio.value && audio.value.pause()
const speech = useSpeechSynthesis(`${user?.nickName}对你说:${message}`, {
voice: window.speechSynthesis.getVoices().find(v => v.name === 'Microsoft Xiaoxiao Online (Natural) - Chinese (Mainland) (zh-CN)') ?? window.speechSynthesis.getVoices().find(v => v.lang.includes('zh-CN')) ?? window.speechSynthesis.getVoices()[0],
lang: 'zh-CN',
pitch: 1,
rate: 1,
})
speech.speak()
}, 1000)
})
})
onUnmounted(() => {
//断开链接
signalR.connection?.stop()
})
const getHistoryData = async () => {
$fetch('/Api/Server/GetServerHistoryDate', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + useCookie('token').value
},
params: {
ServerId: mainLayoutStore.SelectServer.value,
},
baseURL: useRuntimeConfig().public.baseUrl,
}).then((res) => {
const data = res as dataHistoryType
DataStore.dataHistory = data
const datas = data.data
//遍历字典
for (const key in datas) {
if (Object.prototype.hasOwnProperty.call(datas, key)) {
const element = datas[key];
//获取最后一次的数据
DataStore.data[key] = element[element.length - 1];
}
}
DataStore.startTimer()
})
}
onMounted(async () => {
await getHistoryData()
})
watch(() => mainLayoutStore.SelectServer.value, async () => {
await getHistoryData()
})
let isShift = false
onKeyStroke('Shift', (e) => {
e.preventDefault()
setTimeout(() => {
isShift = true
},100)
setTimeout(() => {
isShift = false
},200)
if(isShift){
visible.value = !visible.value
}
},{eventName: 'keyup'})
</script>
<template>
<section class="layout">
<audio ref="audio">
<source src="/audios/idle1.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素
</audio>
<audio ref="audio1">
<source src="/audios/audio_0a383a4c11.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素
</audio>
<audio ref="audio2">
<source src="/audios/bibibi.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素
</audio>
<SideBar/>
<TitleBar/>
<n-modal v-model:show.lazy="visible" auto-focus >
<Term/>
</n-modal>
<div class="main-box">
<n-back-top :right="40" style="z-index: 200"/>
<div ref="mainRef" class="main">
<div class="hero">
<div class="hero-box">
<h3>你好 {{ mainLayoutStore.UserInfo.nickName }}</h3>
<p>欢迎来到龙盾云御,这是基于Nuxt+Vue3的后台管理系统</p>
</div>
<div class="server-dropdown">
<n-select v-model:value="mainLayoutStore.SelectServer.value" :options="ServerList" />
</div>
<HeroBox/>
</div>
<div class="out">
<slot/>
</div>
</div>
</div>
<FloaterBar/>
</section>
</template>
<style lang="scss" scoped>
@import "base";
.layout {
width: 100%;
height: 100vh;
max-width: 100vw;
display: grid;
grid:
"sidebar titlebar" auto
"sidebar main" 1fr
"sidebar folder" auto
/ auto 1fr;
grid-auto-flow: row dense;
}
.main-box {
grid-area: main;
overflow-y: auto;
&::-webkit-scrollbar {
width: 0;
}
}
.main {
display: grid;
width: 100%;
grid-template-rows: 125px 75px 1fr;
will-change: scroll-position;
padding-bottom: 400px;
}
.hero {
grid-row: 1/3;
grid-column: 1;
overflow: hidden;
border-radius: 0 0 $radius*2 $radius*2;
position: relative;
.hero-box {
position: absolute;
z-index: 11;
left: $padding*3;
top: $padding*3;
display: flex;
flex-direction: column;
gap: $gap;
h3, p {
color: #FFF;
font-size: 30px;
font-style: normal;
font-weight: 700;
line-height: normal;
}
p {
font-size: 23px;
font-style: normal;
font-weight: 500;
line-height: 130%; /* 29.9px */
}
}
}
.server-dropdown {
position: absolute;
z-index: 11;
right: $padding*3;
top: $padding*3;
:deep(.n-select>.n-base-selection){
.n-base-selection__border{
border: unset;
}
.n-base-selection-label{
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(400px);
>div{
color: #FFF;
}
}
}
}
.out {
grid-row: 2/4;
grid-column: 1;
z-index: 10;
width: 100%;
display: flex;
padding: 0 20px 20px;
}
:deep(.n-modal-mask){
backdrop-filter: blur(100px);
background: rgba(0,0,0,.7);
}
</style>