LoongPanel-Asp/web/layouts/Main.vue

366 lines
9.5 KiB
Vue
Raw Normal View History

2024-06-22 10:54:02 +08:00
<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";
2024-06-29 18:16:29 +08:00
import {type dataHistoryType, useDataStore} from "~/strores/DataStore";;
2024-06-22 10:54:02 +08:00
const audio = ref<any>(null);
2024-06-29 18:16:29 +08:00
const audio1 = ref<any>(null);
2024-06-22 10:54:02 +08:00
const toast = useToast()
const visible = ref<boolean>(false)
const DataStore = useDataStore()
const {$gsap} = useNuxtApp()
const mainRef = ref<HTMLElement>()
const mainLayoutStore = useMainLayoutStore()
const ServerList = ref<{ name: string, id?: string }[]>([{name: 'Australia'},
{name: 'Brazil'},
{name: 'China'},
{name: 'Egypt'},
{name: 'France'},
{name: 'Germany'},
{name: 'India'},
{name: 'Japan'},
{name: 'Spain'},
{name: 'United States'}])
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;
if (!mainLayoutStore.SelectServer.id) {
mainLayoutStore.SelectServer = data[0];
}
})
})
const signalR = useSessionSignalRStore();
2024-06-29 18:16:29 +08:00
2024-06-22 10:54:02 +08:00
//有且运行一次
onMounted(() => {
signalR.initConnection();
signalR.connection?.on('userJoined', (data: any) => {
mainLayoutStore.setOnlineUsers(data)
console.log(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.id) return
DataStore.setData(type, message)
})
2024-06-29 18:16:29 +08:00
signalR.connection?.on('ReceiveWaring', (value: string,valueName) => {
// //两位小数
// audio1.value.currentTime = 0;
// audio1.value && audio1.value.click()
// audio1.value && audio1.value.play()
// toast.info(`你设定的${valueName}已经达到通知阈值,当前值为 ${value}`,{
// position: POSITION.BOTTOM_RIGHT,
// timeout:5000,
// })
})
signalR.connection?.on('ReceiveNotify', (value: string,valueName) => {
//两位小数
audio1.value.currentTime = 0;
const {
isSupported,
notification,
show,
close,
onClick,
onShow,
onError,
onClose,
} = useWebNotification({
title: 'Hello, VueUse world!',
dir: 'auto',
lang: 'en',
renotify: true,
tag: 'test',
})
if(isSupported.value){
Notification.requestPermission().then(res => {
//如果允许
console.log(res)
})
show()
return
}
audio1.value && audio1.value.click()
audio1.value && audio1.value.play()
toast.info(`你设定的${valueName}已经达到通知阈值,当前值为 ${value}`,{
position: POSITION.BOTTOM_RIGHT,
timeout:5000,
})
})
2024-06-22 10:54:02 +08:00
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()
2024-06-29 18:16:29 +08:00
}, 1000)
2024-06-22 10:54:02 +08:00
})
})
onUnmounted(() => {
//断开链接
signalR.connection?.stop()
})
const getHistoryData = async () => {
$fetch('/Api/Server/GetServerHistoryDate', {
method: 'GET',
headers: {
'Authorization': 'Bearer ' + useCookie('token').value
},
params: {
ServerId: mainLayoutStore.SelectServer.id,
},
baseURL: useRuntimeConfig().public.baseUrl,
}).then((res) => {
const data = res as dataHistoryType
DataStore.dataHistory = data
const datas = data.data
console.log(datas)
//遍历字典
for (const key in datas) {
if (Object.prototype.hasOwnProperty.call(datas, key)) {
const element = datas[key];
//获取最后一次的数据
DataStore.data[key] = element[element.length - 1];
}
}
console.log("dasdas")
DataStore.startTimer()
})
}
onMounted(async () => {
await getHistoryData()
})
watch(() => mainLayoutStore.SelectServer.id, async () => {
await getHistoryData()
})
2024-06-29 18:16:29 +08:00
let isShift = false
2024-06-22 10:54:02 +08:00
onKeyStroke('Shift', (e) => {
e.preventDefault()
2024-06-29 18:16:29 +08:00
setTimeout(() => {
isShift = true
},100)
setTimeout(() => {
isShift = false
},200)
if(isShift){
visible.value = !visible.value
}
},{eventName: 'keyup'})
2024-06-22 10:54:02 +08:00
</script>
<template>
<section class="layout">
<audio ref="audio">
<source src="/audios/idle1.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素
</audio>
2024-06-29 18:16:29 +08:00
<audio ref="audio1">
<source src="/audios/audio_0a383a4c11.mp3" type="audio/mpeg">
您的浏览器不支持 audio 元素
</audio>
2024-06-22 10:54:02 +08:00
<SideBar/>
<TitleBar/>
<Dialog
v-model:visible="visible"
:breakpoints="{ '1199px': '75vw', '575px': '90vw' }"
:pt="{
root: {
style:'border:unset;background-color:unset;'
},
mask: {
style: 'backdrop-filter: blur(20px)'
}
}"
modal
>
<template #container="{ closeCallback }">
<Term/>
</template>
</Dialog>
<div class="main-box">
<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">
<Dropdown v-model="mainLayoutStore.SelectServer" :options="ServerList"
class="server-dropdown-input"
optionLabel="name"
placeholder="选择服务器">
<template #value="slotProps">
<div v-if="slotProps.value">
<div style="color: #FFFFFF;gap: 8px;display: flex;align-items: center">{{ slotProps.value.name }}
<Tag :value="slotProps.value.id"/>
</div>
</div>
<span v-else>
{{ slotProps.placeholder }}
</span>
</template>
<template #option="slotProps">
<div
style="display: flex;align-items: center;justify-content: space-between;width: 100%;">
{{ slotProps.option.name }}
<Tag :value="slotProps.option.id"/>
</div>
</template>
</Dropdown>
</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" 76px
"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: 145px 55px 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*2;
top: $padding;
display: flex;
flex-direction: column;
gap: $gap;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
h3, p {
color: #FFF;
font-size: 40px;
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*2.5;
top: $padding*2;
}
.out {
grid-row: 2/4;
grid-column: 1;
z-index: 10;
width: 100%;
display: flex;
padding: 0 40px 40px;
}
.server-dropdown-input {
background: $primary-color;
color: #FFF;
border: unset;
}
</style>