修改侧边栏
This commit is contained in:
parent
d152997430
commit
1f0275a3a2
|
@ -47,6 +47,11 @@
|
|||
|
||||
<ItemGroup>
|
||||
<Folder Include="Configs\Alerts\" />
|
||||
<Folder Include="wwwroot\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Update="wwwroot\index">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -76,8 +76,8 @@ builder.Services.AddCors(options =>
|
|||
policy =>
|
||||
{
|
||||
//允许全部
|
||||
policy.WithOrigins("http://localhost:3001", "http://192.168.1.12:3001", "http://192.168.1.12:3001",
|
||||
"https://192.168.0.13:3000","https://loongpanel.xn--7p0a.site").AllowAnyHeader().AllowAnyMethod().AllowCredentials();
|
||||
policy.WithOrigins("http://localhost:3001", "http://192.168.1.22:3001", "http://192.168.1.22:3001",
|
||||
"https://192.168.0.22:3000","https://loongpanel.xn--7p0a.site").AllowAnyHeader().AllowAnyMethod().AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://192.168.1.12:58826",
|
||||
"applicationUrl": "http://192.168.1.22:58826",
|
||||
"sslPort": 44304
|
||||
}
|
||||
},
|
||||
|
@ -14,7 +14,7 @@
|
|||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "http://192.168.1.12:5000",
|
||||
"applicationUrl": "http://192.168.1.22:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
|||
"dotnetRunMessages": true,
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "swagger",
|
||||
"applicationUrl": "https://192.168.1.12:7233;http://192.168.1.12:5253",
|
||||
"applicationUrl": "https://192.168.1.22:7233;http://192.168.1.22:5253",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
|
|
|
@ -133,39 +133,167 @@
|
|||
{
|
||||
"description": "Reference a permission or permission set by identifier and extends its scope.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier"
|
||||
],
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"description": "Identifier of the permission or permission set.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/Identifier"
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"identifier"
|
||||
],
|
||||
"properties": {
|
||||
"identifier": {
|
||||
"oneOf": [
|
||||
{
|
||||
"description": "shell:default -> This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-execute -> Enables the execute command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-execute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-kill -> Enables the kill command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-kill"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-open -> Enables the open command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-spawn -> Enables the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-stdin-write -> Enables the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-stdin-write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-execute -> Denies the execute command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-execute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-kill -> Denies the kill command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-kill"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-open -> Denies the open command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-spawn -> Denies the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-stdin-write -> Denies the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-stdin-write"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"allow": {
|
||||
"items": {
|
||||
"title": "Entry",
|
||||
"description": "A command allowed to be executed by the webview API.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"args",
|
||||
"cmd",
|
||||
"name",
|
||||
"sidecar"
|
||||
],
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "The allowed arguments for the command execution.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ShellAllowedArgs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cmd": {
|
||||
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
|
||||
"type": "string"
|
||||
},
|
||||
"sidecar": {
|
||||
"description": "If this command is a sidecar command.",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"deny": {
|
||||
"items": {
|
||||
"title": "Entry",
|
||||
"description": "A command allowed to be executed by the webview API.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"args",
|
||||
"cmd",
|
||||
"name",
|
||||
"sidecar"
|
||||
],
|
||||
"properties": {
|
||||
"args": {
|
||||
"description": "The allowed arguments for the command execution.",
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/definitions/ShellAllowedArgs"
|
||||
}
|
||||
]
|
||||
},
|
||||
"cmd": {
|
||||
"description": "The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.",
|
||||
"type": "string"
|
||||
},
|
||||
"sidecar": {
|
||||
"description": "If this command is a sidecar command.",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"allow": {
|
||||
"description": "Data that defines what is allowed by the scope.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
},
|
||||
"deny": {
|
||||
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"items": {
|
||||
"$ref": "#/definitions/Value"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1165,6 +1293,83 @@
|
|||
"resources:deny-close"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:default -> This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality without any specific\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:default"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-execute -> Enables the execute command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-execute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-kill -> Enables the kill command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-kill"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-open -> Enables the open command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-spawn -> Enables the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:allow-stdin-write -> Enables the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:allow-stdin-write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-execute -> Denies the execute command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-execute"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-kill -> Denies the kill command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-kill"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-open -> Denies the open command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-open"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-spawn -> Denies the spawn command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-spawn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "shell:deny-stdin-write -> Denies the stdin_write command without any pre-configured scope.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"shell:deny-stdin-write"
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "tray:default -> Default permissions for the plugin.",
|
||||
"type": "string",
|
||||
|
@ -2499,6 +2704,45 @@
|
|||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ShellAllowedArg": {
|
||||
"description": "A command argument allowed to be executed by the webview API.",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "A non-configurable argument that is passed to the command in the order it was specified.",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"description": "A variable that is set while calling the command from the webview API.",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"validator"
|
||||
],
|
||||
"properties": {
|
||||
"validator": {
|
||||
"description": "[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\n[regex]: https://docs.rs/regex/latest/regex/#syntax",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"ShellAllowedArgs": {
|
||||
"description": "A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration.",
|
||||
"anyOf": [
|
||||
{
|
||||
"description": "Use a simple boolean to allow all or disable all arguments to this command configuration.",
|
||||
"type": "boolean"
|
||||
},
|
||||
{
|
||||
"description": "A specific set of [`ShellAllowedArg`] that are valid to call for the command configuration.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/ShellAllowedArg"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
import { Slot } from 'expo-router';
|
||||
import {StyleSheet, View,Text} from "react-native";
|
||||
import {useEffect} from "react";
|
||||
|
||||
export default function LoginLayout() {
|
||||
return (
|
||||
<View style={styles.layoutBox}>
|
||||
<View style={styles.background}>
|
||||
<View style={styles.backgroundRectangular1}></View>
|
||||
<View style={styles.backgroundRectangular2}></View>
|
||||
<View style={styles.backgroundEllipse1}></View>
|
||||
<View style={styles.backgroundEllipse2}></View>
|
||||
</View>
|
||||
<Slot />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
layoutBox:{
|
||||
height:'100%',
|
||||
width:'100%',
|
||||
position:'relative',
|
||||
backgroundColor:'white',
|
||||
},
|
||||
background:{
|
||||
position:'absolute',
|
||||
top:0,
|
||||
left:0,
|
||||
width:'100%',
|
||||
height:'100%',
|
||||
zIndex:-1,
|
||||
},
|
||||
backgroundRectangular1:{
|
||||
position:"absolute",
|
||||
width: 372,
|
||||
height: 372,
|
||||
left:'-50%',
|
||||
bottom:'-20%',
|
||||
transform:'rotate(27.089deg)',
|
||||
borderStyle:'solid',
|
||||
borderColor:'#F1F4FF',
|
||||
borderWidth:2,
|
||||
},
|
||||
backgroundRectangular2:{
|
||||
position:"absolute",
|
||||
width: 372,
|
||||
height: 372,
|
||||
left:'-50%',
|
||||
bottom:'-20%',
|
||||
borderStyle:'solid',
|
||||
borderColor:'#F1F4FF',
|
||||
borderWidth:2,
|
||||
},
|
||||
backgroundEllipse1:{
|
||||
position:"absolute",
|
||||
width: 496,
|
||||
height: 496,
|
||||
right:'-40%',
|
||||
top:'-20%',
|
||||
borderRadius:496,
|
||||
borderStyle:'solid',
|
||||
borderColor:'#F1F4FF',
|
||||
borderWidth:3,
|
||||
},
|
||||
backgroundEllipse2:{
|
||||
position:"absolute",
|
||||
width: 635,
|
||||
height: 635,
|
||||
right:'-90%',
|
||||
top:'-38%',
|
||||
borderRadius:496,
|
||||
backgroundColor:'#F8F9FF'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
import {StyleSheet, Text, TouchableOpacity, View} from "react-native";
|
||||
import {Image} from "expo-image";
|
||||
|
||||
export default function Page() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<View style={styles.TextContainer}>
|
||||
<Text>登录</Text>
|
||||
<Text>登录以开始管理您的项目</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
TextContainer: {}
|
||||
})
|
|
@ -0,0 +1,81 @@
|
|||
import {Button, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
|
||||
import { Asset } from 'expo-asset';
|
||||
import { Image } from 'expo-image';
|
||||
import {router} from "expo-router";
|
||||
|
||||
export default function Page() {
|
||||
const wb = require('../../assets/images/welcome_image.png');
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Image source={wb} style={styles.Image} />
|
||||
<View style={styles.textContainer}>
|
||||
<Text style={styles.textTitle}>欢迎来到龙盾云御</Text>
|
||||
<Text style={styles.text}>今天是新的一天。这是你的一天。你塑造它,登录以开始管理你的项目。</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.loginButton} onPress={()=>{
|
||||
router.push("/(login)/login")
|
||||
}}>
|
||||
<Text style={styles.loginButtonText}>登录</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
paddingVertical:80,
|
||||
paddingHorizontal:50,
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
display:'flex',
|
||||
flexDirection:'column',
|
||||
|
||||
},
|
||||
Image:{
|
||||
flex:1,
|
||||
flexBasis:6,
|
||||
width:'100%',
|
||||
resizeMode:'cover',
|
||||
maxHeight:'50%'
|
||||
},
|
||||
textContainer:{
|
||||
flex:1,
|
||||
flexBasis:4,
|
||||
display:'flex',
|
||||
flexDirection:'column',
|
||||
justifyContent:'center',
|
||||
gap:25,
|
||||
alignItems:'center',
|
||||
width:'100%',
|
||||
},
|
||||
textTitle:{
|
||||
color:'#1F41BB',
|
||||
fontSize:35,
|
||||
fontWeight:'800',
|
||||
textAlign:'center'
|
||||
},
|
||||
text:{
|
||||
color:'#000',
|
||||
textAlign:'center',
|
||||
fontSize:16,
|
||||
fontWeight:'500',
|
||||
},
|
||||
loginButton: {
|
||||
backgroundColor: '#1F41BB',
|
||||
width: '100%',
|
||||
padding: 15, // 添加一些内边距
|
||||
borderRadius: 5, // 可选,添加圆角
|
||||
alignItems: 'center', // 水平居中
|
||||
marginTop: 50, // 可选,添加一些顶部外边距
|
||||
shadowOffset: { width: 0, height: 10 }, // 水平偏移和垂直偏移
|
||||
shadowOpacity: 0.5, // 阴影透明度
|
||||
shadowRadius: 10, // 阴影半径
|
||||
elevation: 5, // Android特有的阴影效果,iOS使用shadowRadius
|
||||
shadowColor: '#CBD6FF', // 阴影颜色
|
||||
},
|
||||
loginButtonText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
})
|
|
@ -0,0 +1,19 @@
|
|||
const { getDefaultConfig } = require("expo/metro-config");
|
||||
|
||||
module.exports = (() => {
|
||||
const config = getDefaultConfig(__dirname);
|
||||
|
||||
const { transformer, resolver } = config;
|
||||
|
||||
config.transformer = {
|
||||
...transformer,
|
||||
babelTransformerPath: require.resolve("react-native-svg-transformer/expo")
|
||||
};
|
||||
config.resolver = {
|
||||
...resolver,
|
||||
assetExts: resolver.assetExts.filter((ext) => ext !== "svg"),
|
||||
sourceExts: [...resolver.sourceExts, "svg"]
|
||||
};
|
||||
|
||||
return config;
|
||||
})();
|
|
@ -1 +1 @@
|
|||
NUXT_API_URL="http://192.168.1.12:5000"
|
||||
NUXT_API_URL="http://192.168.1.22:5000"
|
|
@ -3,9 +3,11 @@
|
|||
<template>
|
||||
<div>
|
||||
<NuxtPwaManifest />
|
||||
<n-loading-bar-provider>
|
||||
<NuxtLayout>
|
||||
<NuxtPage />
|
||||
</NuxtLayout>
|
||||
</n-loading-bar-provider>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -2,130 +2,81 @@
|
|||
import {useDataStore} from "~/strores/DataStore";
|
||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||
|
||||
const {$gsap} = useNuxtApp()
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
default: "CPU使用率"
|
||||
default: "CPU使用率",
|
||||
},
|
||||
info:{
|
||||
type:Array,
|
||||
default:()=>[],
|
||||
},
|
||||
unit: {
|
||||
type: String,
|
||||
default: "%"
|
||||
},
|
||||
watcher: {
|
||||
type: String,
|
||||
default: "cpuTotalUsage"
|
||||
type: [String, Array],
|
||||
default: "cpuTotalUsage",
|
||||
validator: (value) => {
|
||||
return typeof value === 'string' || Array.isArray(value);
|
||||
}
|
||||
},
|
||||
reverse: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
const value = ref("0");
|
||||
const trueValue = ref("0");
|
||||
const values=ref<string[]>(Array( Array.isArray(props.watcher)?props.watcher.length:1).fill('0'))
|
||||
const dataStore = useDataStore()
|
||||
const mainStore = useMainLayoutStore()
|
||||
const status=ref<string>("success")
|
||||
//监听dataStore变更
|
||||
dataStore.$subscribe((_, state) => {
|
||||
//获得d3YT#cpuUserUsage的key的value
|
||||
const data = state.data[props.watcher]
|
||||
//如果data为空则不更新
|
||||
if (!data) {
|
||||
value.value = "0"
|
||||
updateProgress(0)
|
||||
if (props.reverse) {
|
||||
value.value = "100"
|
||||
updateProgress(100)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
//如果与data.value 不一致则更新
|
||||
const newValue = (Math.floor(Number(data) * 100) / 100).toFixed(2)
|
||||
|
||||
if (newValue !== value.value) {
|
||||
value.value = newValue
|
||||
trueValue.value = data.toString()
|
||||
//转换为数值
|
||||
updateProgress(parseFloat(value.value))
|
||||
}
|
||||
const watcher = Array.isArray(props.watcher) ? [...props.watcher] : [props.watcher];
|
||||
// 使用map函数从state.data中取出每个watcherKey对应的值
|
||||
values.value = watcher.map(watcherKey => state.data[watcherKey as string]);
|
||||
//检测第一个值超过50则warning 超过80则error
|
||||
const value=Number(values.value[0])
|
||||
status.value = value > 80 ? "error" : value > 50 ? "warning" : "success";
|
||||
})
|
||||
watch(() => mainStore.SelectServer, () => {
|
||||
//立即更新
|
||||
value.value = "0"
|
||||
updateProgress(0)
|
||||
})
|
||||
const circumference = 2 * Math.PI * 36;
|
||||
const updateProgress = (value: number) => {
|
||||
let progress = (100 - value) / 100;
|
||||
if (props.reverse) {
|
||||
progress = 1 - progress
|
||||
}
|
||||
$gsap.to("#" + props.title, {
|
||||
duration: 0.5,
|
||||
ease: 'power1.out',
|
||||
strokeDashoffset: circumference * progress,
|
||||
})
|
||||
$gsap.to("#" + props.title + "Arrow", {
|
||||
duration: 0.4,
|
||||
ease: 'bounce.inOut',
|
||||
rotation: 360 * (value / 100) - 40,
|
||||
transformOrigin: "center center"
|
||||
})
|
||||
let color;
|
||||
if (value >= 0 && value < 20) {
|
||||
color = "#00C853"; // 绿色
|
||||
} else if (value >= 20 && value < 40) {
|
||||
color = "#3A57E8"; // 蓝色
|
||||
} else if (value >= 40 && value < 60) {
|
||||
color = "#FBBD08"; // 黄色
|
||||
} else if (value >= 60 && value < 80) {
|
||||
color = "#FF5722"; // 红色
|
||||
} else if (value >= 80 && value <= 100) {
|
||||
color = "#FF0000"; // 假设80-100是深红色
|
||||
}
|
||||
|
||||
if (color) {
|
||||
$gsap.to("#" + props.title, {
|
||||
duration: 0.5,
|
||||
ease: 'power1.out',
|
||||
stroke: color,
|
||||
});
|
||||
}
|
||||
}
|
||||
onMounted(()=>{
|
||||
updateProgress(0)
|
||||
//从datStore中读取数据
|
||||
nextTick(()=>{
|
||||
updateProgress(Number(dataStore.data[props.watcher]))
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mini-card-box">
|
||||
<svg fill="none" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="36" cy="36" r="32" stroke="#E9ECEF" stroke-width="2"/>
|
||||
<circle :id="title" :stroke-dasharray="circumference" cx="36"
|
||||
cy="36" r="32" stroke="red"
|
||||
stroke-linecap="round"
|
||||
stroke-width="4" transform="rotate(-90, 36, 36)"/>
|
||||
<path
|
||||
:id="title+'Arrow'"
|
||||
d="M26.1904 44.784C25.8209 45.1944 25.854 45.8267 26.2645 46.1963C26.6749 46.5658 27.3072 46.5327 27.6767 46.1223L26.1904 44.784ZM43.7763 27.8042C43.7474 27.2527 43.2768 26.829 42.7253 26.8579L33.7376 27.3289C33.1861 27.3578 32.7624 27.8284 32.7913 28.3799C32.8202 28.9314 33.2908 29.3551 33.8423 29.3262L41.8313 28.9075L42.25 36.8965C42.2789 37.4481 42.7495 37.8717 43.301 37.8428C43.8525 37.8139 44.2762 37.3434 44.2473 36.7919L43.7763 27.8042ZM27.6767 46.1223L43.5208 28.5257L42.0345 27.1874L26.1904 44.784L27.6767 46.1223Z"
|
||||
fill="#ADB5BD"/>
|
||||
</svg>
|
||||
<div class="text">
|
||||
<h3>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<n-popover trigger="hover" placement="bottom">
|
||||
<template #trigger>
|
||||
<div class="mini-card-box">
|
||||
<!-- <svg fill="none" viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg">-->
|
||||
<!-- <circle cx="36" cy="36" r="32" stroke="#E9ECEF" stroke-width="2"/>-->
|
||||
<!-- <circle :id="title" :stroke-dasharray="circumference" cx="36"-->
|
||||
<!-- cy="36" r="32" stroke="red"-->
|
||||
<!-- stroke-linecap="round"-->
|
||||
<!-- stroke-width="4" transform="rotate(-90, 36, 36)"/>-->
|
||||
<!-- <path-->
|
||||
<!-- :id="title+'Arrow'"-->
|
||||
<!-- d="M26.1904 44.784C25.8209 45.1944 25.854 45.8267 26.2645 46.1963C26.6749 46.5658 27.3072 46.5327 27.6767 46.1223L26.1904 44.784ZM43.7763 27.8042C43.7474 27.2527 43.2768 26.829 42.7253 26.8579L33.7376 27.3289C33.1861 27.3578 32.7624 27.8284 32.7913 28.3799C32.8202 28.9314 33.2908 29.3551 33.8423 29.3262L41.8313 28.9075L42.25 36.8965C42.2789 37.4481 42.7495 37.8717 43.301 37.8428C43.8525 37.8139 44.2762 37.3434 44.2473 36.7919L43.7763 27.8042ZM27.6767 46.1223L43.5208 28.5257L42.0345 27.1874L26.1904 44.784L27.6767 46.1223Z"-->
|
||||
<!-- fill="#ADB5BD"/>-->
|
||||
<!-- </svg>-->
|
||||
<n-progress type="dashboard" processing gap-position="bottom" :status="status" :percentage="
|
||||
values[0]
|
||||
" style="width: 4.427vw; max-width:120px;min-width: 80px" />
|
||||
<div class="text">
|
||||
<h3>
|
||||
{{ title }}
|
||||
</h3>
|
||||
<h2>
|
||||
<span>{{ Number(values[0]??0).toFixed(2)}}{{ unit }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<n-tag type="info" v-for="i in info">
|
||||
{{ i }}
|
||||
</n-tag>
|
||||
</n-popover>
|
||||
|
||||
<h2>
|
||||
<span v-if="props.reverse" v-tooltip="`${100-trueValue}${unit}`">{{ 100 - value }}{{ unit }}</span>
|
||||
<span v-else v-tooltip="`${trueValue}${unit}`">{{ value }}{{ unit }}</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -140,7 +91,9 @@ onMounted(()=>{
|
|||
box-shadow: 0 10px 30px 0 rgba(17, 38, 146, 0.05);
|
||||
gap: $gap*3;
|
||||
border: $border;
|
||||
|
||||
*{
|
||||
@include SC_Font()
|
||||
}
|
||||
> svg {
|
||||
width: 68px;
|
||||
height: 68px;
|
||||
|
@ -160,17 +113,16 @@ onMounted(()=>{
|
|||
color: $light-unfocused-color;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-weight: 600;
|
||||
line-height: 175%; /* 28px */
|
||||
//不允许换行
|
||||
text-wrap: nowrap;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 19px;
|
||||
font-weight: 500;
|
||||
font-size: 25px;
|
||||
font-weight: 800;
|
||||
color: $light-text-color;
|
||||
|
||||
.dark-mode & {
|
||||
color: $dark-text-color;
|
||||
}
|
||||
|
|
|
@ -37,13 +37,23 @@ const menu = ref();
|
|||
<Button autofocus label="发送" outlined severity="secondary" @click="sendMessage"/>
|
||||
</template>
|
||||
</Dialog>
|
||||
<n-modal v-model:show="sendMessageModel">
|
||||
123123
|
||||
</n-modal>
|
||||
<ContextMenu ref="menu" :model="items"/>
|
||||
<div v-for="user in mainLayoutStore.OnlineUsers" class="user-item" @click="onRightClick($event,user.id)">
|
||||
<Avatar :image="user.avatar" shape="circle" size="xlarge"/>
|
||||
<n-avatar
|
||||
:size="50"
|
||||
:src="user.avatar"
|
||||
lazy
|
||||
fallback-src="https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg"
|
||||
/>
|
||||
<div class="user-info">
|
||||
<h4>{{ user.nickName }}</h4>
|
||||
<div>
|
||||
<Tag :value="user.posts"/>
|
||||
<n-tag type="info" :bordered="false">
|
||||
{{user.posts}}
|
||||
</n-tag>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -64,7 +74,7 @@ const menu = ref();
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: $gap*3;
|
||||
padding: $padding*.2;
|
||||
padding: $padding*.25 $padding;
|
||||
border-radius: $radius;
|
||||
|
||||
&:hover {
|
||||
|
@ -75,7 +85,7 @@ const menu = ref();
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: $gap;
|
||||
gap: $gap*.2;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ const getServerConfig = () => {
|
|||
$fetch(`/Api/Server/GetServerInfo`, {
|
||||
method: 'GET',
|
||||
params: {
|
||||
serverId: mainLayoutStore.SelectServer.id
|
||||
serverId: mainLayoutStore.SelectServer.value
|
||||
},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
@ -1,20 +1,41 @@
|
|||
<script lang="ts" setup>
|
||||
|
||||
import MiniCard from "~/components/Cards/MiniCard.vue";
|
||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||
import {useDataStore} from "~/strores/DataStore";
|
||||
|
||||
const gridRef = ref<HTMLElement>();
|
||||
const dataStore=useDataStore()
|
||||
const mainLayoutStore=useMainLayoutStore()
|
||||
const CpuUsageCount=ref<string[]>([])
|
||||
const DiskUsageCount=ref<string[]>([])
|
||||
const NetWorkUsageCount=ref<string[]>([])
|
||||
watch(()=>mainLayoutStore.SelectServer.value,()=>{
|
||||
const data=dataStore.data
|
||||
CpuUsageCount.value=Object.keys(data).filter(key => key.startsWith('CpuSingleUsage-'))
|
||||
})
|
||||
onMounted(()=>{
|
||||
const data=dataStore.data
|
||||
CpuUsageCount.value=Object.keys(data).filter(key => key.startsWith('CpuSingleUsage-'))
|
||||
DiskUsageCount.value=Object.keys(data).filter(key => key.startsWith('DiskUtil-'))
|
||||
NetWorkUsageCount.value=Object.keys(data).filter(key => key.startsWith('InterfaceUtilizationPercentage-'))
|
||||
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<n-scrollbar x-scrollable>
|
||||
<div ref="gridRef" class="top-grid-layout">
|
||||
<MiniCard title="系统使用率" watcher="RequestJob"/>
|
||||
<MiniCard title="CPU总使用率" watcher="CpuTotalUsage"/>
|
||||
<MiniCard title="内存总使用率" watcher="MemoryTotalUsage"/>
|
||||
<MiniCard title="读写使用率" watcher="CpuIOWaitUsage"/>
|
||||
<MiniCard title="磁盘总使用率" watcher="DiskTotalUsage"/>
|
||||
<MiniCard title="网络接口使用率" watcher="InterfaceTotalUtilizationPercentage"/>
|
||||
|
||||
<MiniCard title="系统使用率" watcher="RequestJob" :info="['112312']"/>
|
||||
<MiniCard title="CPU总使用率" :watcher="['CpuTotalUsage',...CpuUsageCount]" :info="['AMD EPYC 7K62 (4) @ 2.595GHz','AMD EPYC 7K62 (4) @ 2.595GHz']"/>
|
||||
<MiniCard title="内存总使用率" :watcher="['MemoryTotalUsage','SwapTotalUsage']"/>
|
||||
<MiniCard title="读写使用率" watcher="CpuIOWaitUsage"/>
|
||||
<MiniCard title="磁盘总使用率" :watcher="['DiskTotalUsage',...DiskUsageCount]"/>
|
||||
<MiniCard title="网络接口使用率" :watcher="['InterfaceTotalUtilizationPercentage',...NetWorkUsageCount]"/>
|
||||
</div>
|
||||
</n-scrollbar>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -34,9 +55,4 @@ const gridRef = ref<HTMLElement>();
|
|||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
.top-grid-layout {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -11,7 +11,7 @@ onMounted(()=>{
|
|||
term.open(document.getElementById("terminal") as HTMLElement);
|
||||
const fitAddon = new FitAddon();
|
||||
term.loadAddon(fitAddon);
|
||||
// fitAddon.fit();
|
||||
fitAddon.fit();
|
||||
term.focus();
|
||||
//绑定输入事件
|
||||
term.onData((data) => {
|
||||
|
@ -44,7 +44,7 @@ onMounted(async () => {
|
|||
.catch(err => {
|
||||
console.log("Error while starting connection: " + err);
|
||||
});
|
||||
await connection.invoke("CreateTerminal", mainLayoutStore.SelectServer.id)
|
||||
await connection.invoke("CreateTerminal", mainLayoutStore.SelectServer.value)
|
||||
.then(() => {
|
||||
console.log("Terminal created")
|
||||
})
|
||||
|
|
|
@ -93,7 +93,7 @@ const isOnline = computed(() => {
|
|||
<p>{{ isLock ? '锁定' : '' }}</p>
|
||||
</div>
|
||||
<div class="user-end">
|
||||
<button @click="navigateTo(`userInfo/${userId}`)">
|
||||
<button @click="navigateTo(`settings/userSettings/${userId}`)">
|
||||
<p>查看更多</p>
|
||||
<Icon name="ChevronRight"></Icon>
|
||||
</button>
|
||||
|
|
|
@ -1,185 +1,110 @@
|
|||
<script lang="ts" setup>
|
||||
import Logo from "~/components/Logo.vue";
|
||||
import {ArrowLeft, Search} from 'lucide-vue-next';
|
||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||
|
||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||
import {type MenuOption, NIcon} from "naive-ui";
|
||||
import { LayoutGrid,Computer,Cpu,Cctv,UserRoundCog,Goal,Settings,LogOut,PanelLeftClose,PanelLeftOpen } from 'lucide-vue-next';
|
||||
import type {Component} from "vue";
|
||||
import { useLoadingBar } from 'naive-ui'
|
||||
const {$gsap} = useNuxtApp()
|
||||
const mainLayoutStore = useMainLayoutStore()
|
||||
const Menus =ref([
|
||||
{
|
||||
"label": "系统概览",
|
||||
"icon": "LayoutGrid",
|
||||
"route": "/Home"
|
||||
}, {
|
||||
"label": "主机监测",
|
||||
"icon": "Cpu",
|
||||
"route": "/host/cpu"
|
||||
},{
|
||||
"label": "用户监测",
|
||||
"icon": "Cctv",
|
||||
"route": "/serverUser/all"
|
||||
},{
|
||||
"label": "账号列表",
|
||||
"icon": "UsersRound",
|
||||
"route": "/User"
|
||||
},{
|
||||
"label": "巡检记录",
|
||||
"icon": "PackageSearch",
|
||||
"route": "/InspectionRecords"
|
||||
},
|
||||
{
|
||||
"label": "系统设置",
|
||||
"icon": "Settings",
|
||||
"route": "/Settings/PanelSettings"
|
||||
},
|
||||
])
|
||||
const filteredMenus=computed(()=>{
|
||||
return Menus.value.filter(menu=>{
|
||||
const role=mainLayoutStore.UserInfo.role
|
||||
return menu.label === "账号列表" ? role === "Admin" : true;
|
||||
})
|
||||
})
|
||||
onMounted(() => {
|
||||
const t1 = $gsap.timeline();
|
||||
if (mainLayoutStore.IsLeftSidebarMini) {
|
||||
t1.to(".sidebar-layout", {
|
||||
duration: 0,
|
||||
width: "104px",
|
||||
ease: "power2.out",
|
||||
}, 0)
|
||||
t1.to(".sidebar-layout p,.sidebar-layout h3,.sidebar-layout .aa>svg", {
|
||||
display: "none",
|
||||
duration: 0,
|
||||
}, 0)
|
||||
t1.to(".sidebar-layout .user", {
|
||||
duration: 0,
|
||||
gap: 0
|
||||
}, 0)
|
||||
t1.to(".switch-button", {
|
||||
duration: 0,
|
||||
//旋转3圈
|
||||
rotate: 360 + 180,
|
||||
ease: "power2.out",
|
||||
}, 0)
|
||||
}
|
||||
t1.from(".sidebar-layout", {
|
||||
duration: 0.5,
|
||||
x: "-100%",
|
||||
opacity: 0,
|
||||
ease: "power2.out",
|
||||
})
|
||||
})
|
||||
watch(() => mainLayoutStore.IsLeftSidebarMini, (newValue) => {
|
||||
const t1 = $gsap.timeline();
|
||||
t1.to(".sidebar-layout .header,.folder", {
|
||||
duration: 0.5,
|
||||
x: "-200%",
|
||||
opacity: 0,
|
||||
ease: "power2.out",
|
||||
}, 0)
|
||||
if (newValue) {
|
||||
t1.to(".sidebar-layout", {
|
||||
duration: 0.5,
|
||||
width: "104px",
|
||||
ease: "power2.out",
|
||||
}, 0.5)
|
||||
t1.to(".switch-button", {
|
||||
duration: 1,
|
||||
//旋转3圈
|
||||
rotate: 180,
|
||||
ease: "power2.out",
|
||||
}, 0.5)
|
||||
|
||||
t1.to(".sidebar-layout p,.sidebar-layout h3,.sidebar-layout .aa>svg", {
|
||||
display: "none",
|
||||
duration: 0,
|
||||
}, 0.5)
|
||||
t1.to(".sidebar-layout .user", {
|
||||
duration: 0,
|
||||
gap: 0
|
||||
}, 0.5)
|
||||
} else {
|
||||
t1.to(".sidebar-layout", {
|
||||
duration: 0.5,
|
||||
width: 210,
|
||||
ease: "power2.out",
|
||||
}, 0.5)
|
||||
t1.to(".sidebar-layout", {
|
||||
width: "auto",
|
||||
}, 0.55)
|
||||
t1.to(".switch-button", {
|
||||
duration: 1,
|
||||
y: 0,
|
||||
rotate: 360,
|
||||
ease: "power2.out",
|
||||
}, 0.5)
|
||||
|
||||
t1.to(".sidebar-layout p,.sidebar-layout h3,.sidebar-layout .aa>svg", {
|
||||
display: "block",
|
||||
duration: 0,
|
||||
ease: "power2.out",
|
||||
}, 0.5)
|
||||
t1.to(".sidebar-layout .user", {
|
||||
duration: 0,
|
||||
gap: "1rem"
|
||||
}, 0.5)
|
||||
}
|
||||
t1.to(".sidebar-layout .header,.sidebar-layout .folder", {
|
||||
duration: 0.5,
|
||||
x: 0,
|
||||
opacity: 1,
|
||||
ease: "power2.out",
|
||||
}, 1)
|
||||
})
|
||||
const logout=()=>{
|
||||
$fetch('/Api/Account/Logout', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + useCookie('token').value
|
||||
},
|
||||
baseURL: useRuntimeConfig().public.baseUrl
|
||||
}).then(()=>{
|
||||
navigateTo("/SignIn")
|
||||
})
|
||||
const loadingBar = useLoadingBar()
|
||||
const collapsed=ref<boolean>(false)
|
||||
const activeKey= ref<string | null>(null);
|
||||
function renderIcon(icon: Component) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) })
|
||||
}
|
||||
|
||||
const menuOptions: MenuOption[] = [
|
||||
{
|
||||
label: '系统概览',
|
||||
key: 'home',
|
||||
icon:renderIcon(LayoutGrid)
|
||||
},
|
||||
{
|
||||
label: '主机监测',
|
||||
key: 'host',
|
||||
icon:renderIcon(Computer),
|
||||
children: [
|
||||
{
|
||||
label: 'CPU',
|
||||
key: 'host/cpu',
|
||||
icon:renderIcon(Cpu)
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '用户监测',
|
||||
key: 'serverUser/all',
|
||||
icon:renderIcon(Cctv)
|
||||
},
|
||||
{
|
||||
label:'账号管理',
|
||||
key: 'user',
|
||||
icon:renderIcon(UserRoundCog)
|
||||
},
|
||||
{
|
||||
label: '巡检记录',
|
||||
key: 'inspectionRecords',
|
||||
icon:renderIcon(Goal)
|
||||
},
|
||||
{
|
||||
label: '系统设置',
|
||||
key: 'Settings',
|
||||
icon:renderIcon(Settings)
|
||||
},
|
||||
{
|
||||
label: '退出登录',
|
||||
key: 'Exit',
|
||||
icon:renderIcon(LogOut)
|
||||
}
|
||||
]
|
||||
watch(()=>activeKey.value,async (newValue)=>{
|
||||
loadingBar.start()
|
||||
await navigateTo("/"+newValue)
|
||||
loadingBar.finish()
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="sidebar-layout">
|
||||
<div class="switch-button" @click="mainLayoutStore.toggleLeftSidebarMini()">
|
||||
<ArrowLeft/>
|
||||
</div>
|
||||
<div class="header">
|
||||
<div class="user">
|
||||
<Logo/>
|
||||
<div class="name">
|
||||
<h3>
|
||||
龙盾云御
|
||||
</h3>
|
||||
</div>
|
||||
<transition name="fade" mode="out-in">
|
||||
<div v-if="!collapsed" class="header">
|
||||
<n-image
|
||||
width="45"
|
||||
src="/Square310x310Logo.png"
|
||||
/>
|
||||
<h1>龙盾云御</h1>
|
||||
</div>
|
||||
<div class="search">
|
||||
<Search/>
|
||||
<p>搜索</p>
|
||||
</div>
|
||||
<div class="menus">
|
||||
<div v-for="menu in filteredMenus" v-tooltip="menu.label" class="menu-item" @click="navigateTo(menu.route)" :key="menu.route">
|
||||
<Icon :name="menu.icon"/>
|
||||
<p>{{ menu.label }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="folder">
|
||||
<div class="menu-item" @click="logout">
|
||||
<Icon name="LogOut"/>
|
||||
<p>登出</p>
|
||||
</div>
|
||||
<div class="menu-item aa">
|
||||
<Icon name="Sun"/>
|
||||
<p>颜色模式</p>
|
||||
<color-switch/>
|
||||
<div v-else class="header">
|
||||
<n-image
|
||||
width="45"
|
||||
src="/Square310x310Logo.png"
|
||||
/>
|
||||
<h1 v-if="!collapsed">龙盾云御</h1>
|
||||
</div>
|
||||
</transition>
|
||||
<n-layout has-sider>
|
||||
<n-layout-sider
|
||||
collapse-mode="width"
|
||||
:collapsed-width="64"
|
||||
:collapsed="collapsed"
|
||||
@collapse="collapsed = true"
|
||||
@expand="collapsed = false"
|
||||
:width="200"
|
||||
>
|
||||
<n-menu
|
||||
:collapsed="collapsed"
|
||||
v-model:value="activeKey"
|
||||
:collapsed-width="64"
|
||||
:collapsed-icon-size="22"
|
||||
:options="menuOptions"
|
||||
/>
|
||||
</n-layout-sider>
|
||||
</n-layout>
|
||||
<div class="bottom">
|
||||
<PanelLeftOpen v-if="collapsed" @click="collapsed=false" />
|
||||
<PanelLeftClose v-else @click="collapsed=true" />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
@ -190,11 +115,10 @@ const logout=()=>{
|
|||
.sidebar-layout {
|
||||
display: flex;
|
||||
grid-area: sidebar;
|
||||
padding: 24px 24px 32px 24px;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
flex-shrink: 0;
|
||||
gap: $gap;
|
||||
background: $light-bg-color;
|
||||
position: relative;
|
||||
*{
|
||||
|
@ -205,149 +129,38 @@ const logout=()=>{
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
.fade-enter-active {
|
||||
transition: opacity 0.5s ease;
|
||||
}
|
||||
.fade-leave-active{
|
||||
transition: opacity 0.05s ease;
|
||||
}
|
||||
|
||||
/* 进入开始状态和离开结束状态 */
|
||||
.fade-enter-from, .fade-leave-to {
|
||||
opacity: 0;
|
||||
scale: 0;
|
||||
|
||||
}
|
||||
|
||||
.header {
|
||||
height: 76px;
|
||||
display: flex;
|
||||
gap: 44px;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
&::-webkit-scrollbar{
|
||||
width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.user {
|
||||
display: flex;
|
||||
gap: $gap*2;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
|
||||
> svg {
|
||||
height: 44px;
|
||||
width: 44px;
|
||||
|
||||
}
|
||||
|
||||
.name {
|
||||
h3, p {
|
||||
color: #09090A;
|
||||
font-size: 24px;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
line-height: normal;
|
||||
|
||||
.dark-mode & {
|
||||
color: #FFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
width: 100%;
|
||||
padding: $padding;
|
||||
background: $light-bg-underline-color;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $gap*2;
|
||||
border-radius: $radius*2;
|
||||
|
||||
.dark-mode & {
|
||||
background: $dark-bg-underline-color;
|
||||
|
||||
svg, p {
|
||||
color: #FFF;
|
||||
stroke: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
> p {
|
||||
color: #2A2A2E;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 140%; /* 22.4px */
|
||||
}
|
||||
}
|
||||
|
||||
.menus {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $gap*3;
|
||||
height: 100%;
|
||||
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
padding: $padding;
|
||||
gap: $gap*2;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: $radius;
|
||||
|
||||
|
||||
.dark-mode & {
|
||||
> svg, p {
|
||||
color: #FFF;
|
||||
stroke: #FFF;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $dark-bg-underline-color;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $light-bg-underline-color;
|
||||
}
|
||||
|
||||
> svg {
|
||||
stroke: #09090A;
|
||||
}
|
||||
|
||||
> p {
|
||||
color: #09090A;
|
||||
font-size: 16px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 140%; /* 22.4px */
|
||||
}
|
||||
}
|
||||
|
||||
.folder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
gap: $gap;
|
||||
|
||||
}
|
||||
|
||||
.switch-button {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
right: -15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
background: $primary-color;
|
||||
color: #FFF;
|
||||
border-radius: $radius*100;
|
||||
box-shadow: 0 2px 4px 0 rgba(138, 146, 166, 0.30);
|
||||
|
||||
> svg {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
h1{
|
||||
font-size: 30px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.bottom{
|
||||
height: 49px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -1,34 +1,31 @@
|
|||
<script lang="ts" setup>
|
||||
import {useMainLayoutStore} from "~/strores/UseMainLayoutStore";
|
||||
import {BellRing, Mail} from 'lucide-vue-next';
|
||||
import SidebarRight from "~/components/SidebarRight.vue";
|
||||
import { Signature } from 'lucide-vue-next';
|
||||
|
||||
const {$gsap} = useNuxtApp()
|
||||
const mainLayoutStore = useMainLayoutStore()
|
||||
const home = ref({
|
||||
icon: 'pi pi-home'
|
||||
});
|
||||
const router = useRouter()
|
||||
const routes=computed(()=>{
|
||||
const route=router.currentRoute.value.name as string
|
||||
return route.split('-').map(x => {
|
||||
return {
|
||||
label: x.charAt(0).toUpperCase() + x.slice(1),
|
||||
icon: 'pi pi-angle'
|
||||
}
|
||||
return x.charAt(0).toUpperCase() + x.slice(1)
|
||||
})
|
||||
})
|
||||
const visibleRight = ref(false)
|
||||
const value=ref()
|
||||
const options = ref(['@gmail.com', '@outlook.com', '@yahoo.com'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="title-bar-layout">
|
||||
<Sidebar v-model:visible="visibleRight" header="通知" position="right">
|
||||
<SidebarRight/>
|
||||
</Sidebar>
|
||||
<h1 class="name">
|
||||
<Breadcrumb :home="home" :model="routes" />
|
||||
</h1>
|
||||
<n-auto-complete
|
||||
v-model:value="value"
|
||||
:input-props="{
|
||||
autocomplete: 'disabled',
|
||||
}"
|
||||
:options="options"
|
||||
placeholder="搜索"
|
||||
clearable
|
||||
/>
|
||||
<div class="action">
|
||||
<Icon name="BellRing" @click="visibleRight=true" :stroke-width="1.5" :size="20"/>
|
||||
<Icon name="Mail" :stroke-width="1.5" :size="20"/>
|
||||
|
@ -49,7 +46,7 @@ const visibleRight = ref(false)
|
|||
grid-template-columns: auto 1fr auto auto;
|
||||
grid-template-rows: 1fr;
|
||||
align-items: center;
|
||||
padding: 0 $padding*2;
|
||||
padding: 0 $padding;
|
||||
gap: $gap*2;
|
||||
@include SC_Font();
|
||||
.dark-mode & {
|
||||
|
@ -57,6 +54,20 @@ const visibleRight = ref(false)
|
|||
}
|
||||
}
|
||||
|
||||
:deep(.n-breadcrumb){
|
||||
ul{
|
||||
display: flex;
|
||||
padding: 0;
|
||||
align-content: center;
|
||||
|
||||
li>span{
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 700;
|
||||
font-size: 26px;
|
||||
|
|
|
@ -7,7 +7,7 @@ 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 {type dataHistoryType, useDataStore} from "~/strores/DataStore";
|
||||
|
||||
const audio = ref<any>(null);
|
||||
const audio1 = ref<any>(null);
|
||||
|
@ -18,16 +18,7 @@ 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 ServerList = ref<{ label: string, value: string }[]>([])
|
||||
|
||||
const {isScrolling} = useScroll(mainRef)
|
||||
watch(isScrolling, (newValue) => {
|
||||
|
@ -57,10 +48,10 @@ onMounted(() => {
|
|||
},
|
||||
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 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];
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -72,14 +63,13 @@ 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
|
||||
if (id !== mainLayoutStore.SelectServer.value) return
|
||||
DataStore.setData(type, message)
|
||||
})
|
||||
signalR.connection?.on('ReceiveWaring', (value: string,valueName) => {
|
||||
|
@ -97,13 +87,7 @@ onMounted(() => {
|
|||
audio1.value.currentTime = 0;
|
||||
const {
|
||||
isSupported,
|
||||
notification,
|
||||
show,
|
||||
close,
|
||||
onClick,
|
||||
onShow,
|
||||
onError,
|
||||
onClose,
|
||||
} = useWebNotification({
|
||||
title: `你设定的${valueName}已经达到通知阈值,当前值为 ${value}`,
|
||||
dir: 'auto',
|
||||
|
@ -157,14 +141,13 @@ const getHistoryData = async () => {
|
|||
'Authorization': 'Bearer ' + useCookie('token').value
|
||||
},
|
||||
params: {
|
||||
ServerId: mainLayoutStore.SelectServer.id,
|
||||
ServerId: mainLayoutStore.SelectServer.value,
|
||||
},
|
||||
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)) {
|
||||
|
@ -173,14 +156,13 @@ const getHistoryData = async () => {
|
|||
DataStore.data[key] = element[element.length - 1];
|
||||
}
|
||||
}
|
||||
console.log("dasdas")
|
||||
DataStore.startTimer()
|
||||
})
|
||||
}
|
||||
onMounted(async () => {
|
||||
await getHistoryData()
|
||||
})
|
||||
watch(() => mainLayoutStore.SelectServer.id, async () => {
|
||||
watch(() => mainLayoutStore.SelectServer.value, async () => {
|
||||
await getHistoryData()
|
||||
})
|
||||
let isShift = false
|
||||
|
@ -215,24 +197,11 @@ onKeyStroke('Shift', (e) => {
|
|||
</audio>
|
||||
<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>
|
||||
<n-modal v-model:show.lazy="visible" auto-focus style="max-width: 80vw" >
|
||||
<Term/>
|
||||
</n-modal>
|
||||
<div class="main-box">
|
||||
<n-back-top :right="50" style="z-index: 200"/>
|
||||
<div ref="mainRef" class="main">
|
||||
<div class="hero">
|
||||
<div class="hero-box">
|
||||
|
@ -240,29 +209,7 @@ onKeyStroke('Shift', (e) => {
|
|||
<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>
|
||||
<n-select v-model:value="mainLayoutStore.SelectServer.value" :options="ServerList" />
|
||||
</div>
|
||||
<HeroBox/>
|
||||
</div>
|
||||
|
@ -272,7 +219,6 @@ onKeyStroke('Shift', (e) => {
|
|||
</div>
|
||||
</div>
|
||||
<FloaterBar/>
|
||||
|
||||
</section>
|
||||
</template>
|
||||
|
||||
|
@ -324,7 +270,6 @@ onKeyStroke('Shift', (e) => {
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $gap;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
|
||||
h3, p {
|
||||
color: #FFF;
|
||||
|
@ -348,6 +293,18 @@ onKeyStroke('Shift', (e) => {
|
|||
z-index: 11;
|
||||
right: $padding*2.5;
|
||||
top: $padding*2;
|
||||
: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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -360,10 +317,6 @@ onKeyStroke('Shift', (e) => {
|
|||
padding: 0 40px 40px;
|
||||
}
|
||||
|
||||
.server-dropdown-input {
|
||||
background: $primary-color;
|
||||
color: #FFF;
|
||||
border: unset;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
|
@ -2,12 +2,10 @@ import {defineNuxtRouteMiddleware} from "#app";
|
|||
import {useToast} from 'vue-toastification'
|
||||
|
||||
|
||||
|
||||
export default defineNuxtRouteMiddleware(async (to, from) => {
|
||||
const toast = useToast();
|
||||
const runtimeConfig = useRuntimeConfig();
|
||||
const token = useCookie('token').value;
|
||||
|
||||
if (!token) {
|
||||
toast.error('未登录', {timeout: 3000})
|
||||
return navigateTo("/SignIn");
|
||||
|
|
|
@ -1,59 +1,102 @@
|
|||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
|
||||
|
||||
export default defineNuxtConfig({
|
||||
devtools: {enabled: true},
|
||||
ssr: false,
|
||||
modules: ['@nuxtjs/color-mode', '@hypernym/nuxt-gsap', "@nuxt/image", "@nuxtjs/google-fonts", "nuxt-primevue", 'nuxt-lucide-icons', '@pinia/nuxt', '@pinia-plugin-persistedstate/nuxt', "@vite-pwa/nuxt", "@vueuse/nuxt"],
|
||||
pwa: {
|
||||
manifest: {
|
||||
name: "pwa nuxt 3",
|
||||
short_name: "pwa nuxt",
|
||||
theme_color: '#FFFFFF',
|
||||
description: "Arman Abi r.man.abi@gmail.com",
|
||||
icons: [{
|
||||
src: '/pwa-192x192.png', sizes: "192x192", type: "image/png"
|
||||
},]
|
||||
devtools: {enabled: true},
|
||||
ssr: false,
|
||||
modules: [
|
||||
'@nuxtjs/color-mode',
|
||||
'@hypernym/nuxt-gsap',
|
||||
"@nuxt/image",
|
||||
"@nuxtjs/google-fonts",
|
||||
'nuxt-lucide-icons',
|
||||
'@pinia/nuxt',
|
||||
'@pinia-plugin-persistedstate/nuxt',
|
||||
"@vite-pwa/nuxt",
|
||||
"@vueuse/nuxt",
|
||||
"nuxtjs-naive-ui"
|
||||
],
|
||||
vite: {
|
||||
plugins: [
|
||||
AutoImport({
|
||||
imports: [
|
||||
{
|
||||
'naive-ui': [
|
||||
'useDialog',
|
||||
'useMessage',
|
||||
'useNotification',
|
||||
'useLoadingBar'
|
||||
]
|
||||
}
|
||||
]
|
||||
}),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()]
|
||||
})
|
||||
]
|
||||
},
|
||||
pwa: {
|
||||
manifest: {
|
||||
name: "pwa nuxt 3",
|
||||
short_name: "pwa nuxt",
|
||||
theme_color: '#FFFFFF',
|
||||
description: "Arman Abi r.man.abi@gmail.com",
|
||||
icons: [{
|
||||
src: '/pwa-192x192.png', sizes: "192x192", type: "image/png"
|
||||
},]
|
||||
|
||||
|
||||
}, workbox: {
|
||||
navigateFallback: "/SignIn",
|
||||
}, workbox: {
|
||||
navigateFallback: "/SignIn",
|
||||
|
||||
}, devOptions: {
|
||||
enabled: true, type: "module"
|
||||
}
|
||||
}, devOptions: {
|
||||
enabled: true, type: "module"
|
||||
}
|
||||
|
||||
},
|
||||
gsap: {
|
||||
autoImport: true,
|
||||
extraPlugins: {
|
||||
text: true
|
||||
}
|
||||
},
|
||||
css: ['assets/min.scss', 'primevue/resources/themes/aura-light-green/theme.css', 'primeicons/primeicons.css', 'vue-toastification/dist/index.css'],
|
||||
devServer: {
|
||||
port: 3001, host: '0.0.0.0',
|
||||
// https: {
|
||||
// key: "./localhost+3-key.pem",
|
||||
// cert: "./localhost+3.pem",
|
||||
// }
|
||||
},
|
||||
plugins: [
|
||||
{src: '~/plugins/vue-toast.ts'},
|
||||
{src: '~/plugins/apexcharts.ts'},
|
||||
],
|
||||
runtimeConfig: {
|
||||
baseUrl: '', public: {
|
||||
apiBase: '/Api', baseUrl: process.env.NUXT_API_URL
|
||||
}
|
||||
},
|
||||
googleFonts: {
|
||||
families: {
|
||||
Roboto: true, 'Josefin+Sans': true, Lato: [100, 300], Raleway: {
|
||||
wght: [100, 400], ital: [100]
|
||||
}, Inter: '200..700', 'Crimson Pro': {
|
||||
wght: '200..900', ital: '200..700',
|
||||
}, 'Noto Sans SC': {
|
||||
wght: '200..900', ital: '200..700'
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
gsap: {
|
||||
autoImport: true,
|
||||
extraPlugins: {
|
||||
text: true
|
||||
}
|
||||
},
|
||||
|
||||
css: ['assets/min.scss', 'vue-toastification/dist/index.css'],
|
||||
|
||||
devServer: {
|
||||
port: 3001, host: '0.0.0.0',
|
||||
// https: {
|
||||
// key: "./localhost+3-key.pem",
|
||||
// cert: "./localhost+3.pem",
|
||||
// }
|
||||
},
|
||||
|
||||
plugins: [
|
||||
{src: '~/plugins/vue-toast.ts'},
|
||||
{src: '~/plugins/apexcharts.ts'},
|
||||
],
|
||||
|
||||
runtimeConfig: {
|
||||
baseUrl: '', public: {
|
||||
apiBase: '/Api', baseUrl: process.env.NUXT_API_URL
|
||||
}
|
||||
},
|
||||
|
||||
googleFonts: {
|
||||
families: {
|
||||
Roboto: true, 'Josefin+Sans': true, Lato: [100, 300], Raleway: {
|
||||
wght: [100, 400], ital: [100]
|
||||
}, Inter: '200..700', 'Crimson Pro': {
|
||||
wght: '200..900', ital: '200..700',
|
||||
}, 'Noto Sans SC': {
|
||||
wght: '200..900', ital: '200..700'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
compatibilityDate: '2024-07-21',
|
||||
})
|
File diff suppressed because it is too large
Load Diff
|
@ -23,10 +23,14 @@
|
|||
"grid-layout-plus": "^1.0.5",
|
||||
"lodash": "^4.17.21",
|
||||
"md-editor-v3": "^4.17.0",
|
||||
"naive-ui": "^2.39.0",
|
||||
"nuxt": "^3.11.2",
|
||||
"nuxt-primevue": "^3.0.0",
|
||||
"nuxtjs-naive-ui": "^1.0.2",
|
||||
"patch-package": "^8.0.0",
|
||||
"primeicons": "^7.0.0",
|
||||
"unplugin-auto-import": "^0.18.0",
|
||||
"unplugin-vue-components": "^0.27.3",
|
||||
"uuid": "^9.0.1",
|
||||
"vue": "^3.4.27",
|
||||
"vue-echarts": "^6.7.3",
|
||||
|
@ -52,5 +56,6 @@
|
|||
"sass": "^1.77.4",
|
||||
"vue3-draggable-grid": "^0.0.6",
|
||||
"vue3-puzzle-vcode": "^1.1.7"
|
||||
}
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ const mainLayoutStore=useMainLayoutStore()
|
|||
<Icon name="Settings2"/>
|
||||
<p>平台设置</p>
|
||||
</div>
|
||||
<div >
|
||||
<Icon name="UserRoundCog"/>
|
||||
<div @click="navigateTo(`/settings/userSettings/${mainLayoutStore.UserInfo.id}`)" >
|
||||
<Icon name="UserRoundCog" />
|
||||
<p>账号设置</p>
|
||||
</div>
|
||||
<div @click="navigateTo('/settings/alertSettings')">
|
||||
|
@ -39,14 +39,22 @@ const mainLayoutStore=useMainLayoutStore()
|
|||
display: grid;
|
||||
grid-template-columns: auto 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
min-height: 800px;
|
||||
min-height: 74.645vh;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
gap: $gap*2;
|
||||
|
||||
}
|
||||
.setting-list,.setting-content{
|
||||
background: $light-bg-color;
|
||||
border: $border;
|
||||
border-radius: $radius;
|
||||
color: $light-text-color;
|
||||
overflow: hidden;
|
||||
.dark-mode &{
|
||||
background: $dark-bg-color;
|
||||
color: $dark-text-color;
|
||||
}
|
||||
}
|
||||
.setting-list{
|
||||
display: flex;
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-info-layout">
|
||||
<div class="user-info-bar"></div>
|
||||
<div class="user-avatar">
|
||||
<Avatar size="xlarge" shape="circle" class="avatar" image="https://api.multiavatar.com/asdasd.svg"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "../../../base";
|
||||
.user-info-layout{
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.user-info-bar{
|
||||
height: 3.415vh;
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
</style>
|
|
@ -37,7 +37,7 @@ onMounted(() => {
|
|||
:user-id="user.id"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>c
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import "base";
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
<script setup lang="ts">
|
||||
definePageMeta({
|
||||
layout: 'main',
|
||||
middleware: ['auth']
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="user-info-layout">
|
||||
<div class="user-card">
|
||||
<div class="user-card-top">
|
||||
<Avatar size="xlarge" shape="circle" class="avatar" image="https://api.multiavatar.com/asdasd.svg"/>
|
||||
<h2>sdasdas</h2>
|
||||
<p>1231231231sdasd2</p>
|
||||
<Tag>思科交换机哈克斯的</Tag>
|
||||
</div>
|
||||
<div class="user-card-bottom">
|
||||
<div>
|
||||
<p>asdas</p>
|
||||
<p>sadasd</p>
|
||||
</div><div>
|
||||
<p>asdas</p>
|
||||
<p>sadasd</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-info"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "base";
|
||||
.user-info-layout{
|
||||
width: 100%;
|
||||
display: grid;
|
||||
min-height: 800px;
|
||||
border-radius: $radius;
|
||||
grid-template-columns: minmax(300px,400px) 3fr;
|
||||
gap: $gap*4;
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
.user-card{
|
||||
background: $light-bg-color;
|
||||
border-radius: $radius;
|
||||
border: 1px solid rgba(51, 51, 51, 0.17);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
.user-card-top{
|
||||
padding: $padding*3;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
.p-avatar{
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
h2{
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
p{
|
||||
color: #333;
|
||||
//字符间距
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.p-tag{
|
||||
letter-spacing: 1px;
|
||||
font-size: 13px;
|
||||
padding: $padding*.5;
|
||||
}
|
||||
}
|
||||
.user-card-bottom{
|
||||
border-top: 1px solid rgba(51, 51, 51, 0.17);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $gap;
|
||||
padding: $padding $padding 0;
|
||||
div{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p{
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-info{
|
||||
background: $light-bg-color;
|
||||
border-radius: $radius;
|
||||
padding: $padding*3;
|
||||
border: 1px solid rgba(51, 51, 51, 0.17);
|
||||
}
|
||||
</style>
|
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
|
@ -48,7 +48,7 @@ export const useMainLayoutStore = defineStore('MainLayoutStore', {
|
|||
state: () => {
|
||||
return {
|
||||
IsLeftSidebarMini: false,
|
||||
SelectServer: <{ name: string, id?: string }>{}, // 选中的服务器
|
||||
SelectServer: <{ label: string, value: string }>{}, // 选中的服务器
|
||||
UserInfo: <UserInfoType>{},
|
||||
OnlineUsers: <OnlineUser[]>[],
|
||||
ServerConfig: <{ key: string, value: string }[]>[], // 服务器配置
|
||||
|
|
3253
web/yarn.lock
3253
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue