mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-12 07:10:43 +08:00
🚀 0.4.3
拆分点阵背景图为独立组件,支持显示控制; config挂上reactive,支持动态响应,未来更优雅的支持配置; 执行setting的custom_code;
This commit is contained in:
parent
70dbd77f19
commit
4e2ff5b84e
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nazhua",
|
||||
"version": "0.4.2",
|
||||
"version": "0.4.3",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@ -16,6 +16,7 @@ window.$$nazhuaConfig = {
|
||||
// hideListItemBill: false, // 隐藏列表项的账单信息
|
||||
// hideFilter: false, // 隐藏筛选
|
||||
// hideTag: false, // 隐藏标签
|
||||
// hideDotBG: true, // 隐藏框框里面的点点背景
|
||||
// customCodeMap: {}, // 自定义的地图点信息
|
||||
// nezhaVersion: 'v1', // 哪吒版本
|
||||
// apiMonitorPath: '/api/v1/monitor/{id}',
|
||||
|
||||
83
src/components/dot-dot-box.vue
Normal file
83
src/components/dot-dot-box.vue
Normal file
@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div
|
||||
class="dot-dot-box"
|
||||
:class="{
|
||||
'dot-dot-box--hide': $config.nazhua?.hideDotBG === true,
|
||||
}"
|
||||
:style="boxStyle"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
/**
|
||||
* 点格子背景盒子
|
||||
*/
|
||||
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
borderRadius: {
|
||||
type: [String, Number],
|
||||
default: 12,
|
||||
},
|
||||
padding: {
|
||||
type: [String, Number],
|
||||
default: 20,
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: '#eee',
|
||||
},
|
||||
});
|
||||
|
||||
const boxStyle = computed(() => {
|
||||
const style = {};
|
||||
if (props.borderRadius) {
|
||||
if (typeof props.borderRadius === 'number') {
|
||||
style['--border-radius'] = `${props.borderRadius}px`;
|
||||
} else {
|
||||
style['--border-radius'] = `${props.borderRadius}`;
|
||||
}
|
||||
}
|
||||
if (props.padding) {
|
||||
if (typeof props.padding === 'number') {
|
||||
style.padding = `${props.padding}px`;
|
||||
} else {
|
||||
style.padding = props.padding;
|
||||
}
|
||||
}
|
||||
if (props.color) {
|
||||
style.color = props.color;
|
||||
}
|
||||
return style;
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dot-dot-box {
|
||||
--border-radius: 12px;
|
||||
color: #eee;
|
||||
border-radius: var(--border-radius);
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.6) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
|
||||
&--hide {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -1,17 +1,10 @@
|
||||
import {
|
||||
reactive,
|
||||
} from 'vue';
|
||||
|
||||
const defaultNezhaVersion = import.meta.env.VITE_NEZHA_VERSION;
|
||||
|
||||
const config = {
|
||||
request: {
|
||||
headers: {
|
||||
// 如果设置的是json请求。api的defaultContentType为false的时候,contentType为form请求,反之亦如此
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
codeField: 'code', // code字段
|
||||
dataField: 'result', // 数据字段
|
||||
msgField: 'message', // 消息字段
|
||||
okCode: '0', // 数据通过code
|
||||
limit: 10,
|
||||
},
|
||||
const config = reactive({
|
||||
nazhua: {
|
||||
title: '哪吒监控',
|
||||
nezhaVersion: ['v0', 'v1'].includes(defaultNezhaVersion) ? defaultNezhaVersion : 'v0',
|
||||
@ -27,7 +20,7 @@ const config = {
|
||||
// 解构载入自定义配置
|
||||
...(window.$$nazhuaConfig || {}),
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
export function mergeNazhuaConfig(customConfig) {
|
||||
Object.keys(customConfig).forEach((key) => {
|
||||
|
||||
@ -19,6 +19,10 @@
|
||||
{{ version }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
ref="dynamicContentRef"
|
||||
v-html="dynamicContent"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -27,7 +31,56 @@
|
||||
* Footer
|
||||
*/
|
||||
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
watch,
|
||||
onMounted,
|
||||
nextTick,
|
||||
} from 'vue';
|
||||
import { useStore } from 'vuex';
|
||||
|
||||
const version = import.meta.env.VITE_APP_VERSION;
|
||||
const store = useStore();
|
||||
const dynamicContentRef = ref();
|
||||
|
||||
const dynamicContent = computed(() => {
|
||||
if (store.state.setting?.custom_code) {
|
||||
return store.state.setting.custom_code;
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
// 执行动态脚本的方法
|
||||
const executeScripts = () => {
|
||||
nextTick(() => {
|
||||
if (!dynamicContentRef.value) return;
|
||||
const scripts = dynamicContentRef.value.querySelectorAll('script');
|
||||
scripts.forEach((script) => {
|
||||
const newScript = document.createElement('script');
|
||||
newScript.type = 'text/javascript';
|
||||
if (script.src) {
|
||||
newScript.src = script.src; // 拷贝外部脚本的 src
|
||||
} else {
|
||||
newScript.textContent = script.textContent; // 拷贝内联脚本
|
||||
}
|
||||
document.body.appendChild(newScript);
|
||||
document.body.removeChild(newScript); // 可选:移除以保持整洁
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
watch(dynamicContent, () => {
|
||||
if (dynamicContent.value) {
|
||||
executeScripts();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (dynamicContent.value) {
|
||||
executeScripts();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@ -255,15 +255,7 @@ const serverStat = computed(() => {
|
||||
};
|
||||
});
|
||||
|
||||
const title = computed(() => {
|
||||
if (window.$$nazhuaConfig?.title) {
|
||||
return window.$$nazhuaConfig.title;
|
||||
}
|
||||
if (store.state.setting?.site_name) {
|
||||
return store.state.setting.site_name;
|
||||
}
|
||||
return config.nazhua.title;
|
||||
});
|
||||
const title = computed(() => config.nazhua.title);
|
||||
|
||||
const headerClass = computed(() => {
|
||||
const classes = [];
|
||||
@ -447,7 +439,7 @@ onMounted(() => {
|
||||
align-items: center;
|
||||
gap: 0 20px;
|
||||
|
||||
.login-link {
|
||||
.dashboard-url {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0 5px;
|
||||
@ -455,7 +447,7 @@ onMounted(() => {
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
color: #ff9a00;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,8 +4,13 @@ import 'font-logos/assets/font-logos.css';
|
||||
import './assets/scss/base.scss';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import config from './config';
|
||||
|
||||
import DotDotBox from './components/dot-dot-box.vue';
|
||||
|
||||
export default (app) => {
|
||||
app.use(router);
|
||||
app.use(store);
|
||||
app.component('DotDotBox', DotDotBox);
|
||||
app.config.globalProperties.$config = config;
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="server-info-box">
|
||||
<dot-dot-box class="server-info-box">
|
||||
<div class="server-info-group server-info--cpu">
|
||||
<div class="server-info-label">
|
||||
CPU
|
||||
@ -182,7 +182,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dot-dot-box>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -296,19 +296,6 @@ const processCount = computed(() => props.info?.State?.ProcessCount);
|
||||
.server-info-box {
|
||||
--server-info-item-size: 24px;
|
||||
|
||||
padding: 20px;
|
||||
color: #eee;
|
||||
border-radius: 12px;
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.6) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
@media screen and (max-width: 480px) {
|
||||
--server-info-item-size: 30px;
|
||||
}
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
<template>
|
||||
<div
|
||||
<dot-dot-box
|
||||
v-if="monitorData.length"
|
||||
class="server-monitor-group"
|
||||
padding="16px 20px"
|
||||
>
|
||||
<div class="module-head-group">
|
||||
<div class="left-box">
|
||||
@ -32,7 +33,7 @@
|
||||
:date-list="monitorChartData.dateList"
|
||||
:value-list="monitorChartData.valueList"
|
||||
/>
|
||||
</div>
|
||||
</dot-dot-box>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -168,20 +169,7 @@ onUnmounted(() => {
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.server-monitor-group {
|
||||
padding: 16px 20px;
|
||||
border-radius: 12px;
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.6) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
--line-chart-size: 270px;
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
.module-head-group {
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<div class="server-head">
|
||||
<dot-dot-box
|
||||
class="server-head"
|
||||
padding="16px"
|
||||
>
|
||||
<div class="server-flag">
|
||||
<div class="server-flag-font">
|
||||
<span
|
||||
@ -59,7 +62,7 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</dot-dot-box>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -94,13 +97,7 @@ const cpuInfo = computed(() => hostUtils.getCPUInfo(props.info?.Host?.CPU?.[0]))
|
||||
.server-head {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.8) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
transition: 0.3s;
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
.server-flag {
|
||||
--flag-size: 72px;
|
||||
|
||||
@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<div class="server-status-and-real-time">
|
||||
<dot-dot-box
|
||||
padding="15px"
|
||||
class="server-status-and-real-time"
|
||||
:class="{
|
||||
'status-type--progress': componentName === 'progress',
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="server-status-group"
|
||||
:class="'type--' + componentName + ' status-list--' + serverStatusList.length"
|
||||
@ -17,7 +23,7 @@
|
||||
/>
|
||||
</div>
|
||||
<server-list-item-real-time :info="info" />
|
||||
</div>
|
||||
</dot-dot-box>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -64,25 +70,23 @@ const {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.6) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
--real-time-value-font-size: 36px;
|
||||
--real-time-text-font-size: 16px;
|
||||
--real-time-label-font-size: 16px;
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
--real-time-value-font-size: 30px;
|
||||
&.status-type--progress {
|
||||
--real-time-value-font-size: 24px;
|
||||
--real-time-text-font-size: 14px;
|
||||
--real-time-label-font-size: 14px;
|
||||
|
||||
@media screen and (max-width: 1024px) {
|
||||
--real-time-value-font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
@media screen and (max-width: 1024px) {
|
||||
--real-time-value-font-size: 30px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 720px) {
|
||||
|
||||
@ -2,6 +2,9 @@
|
||||
<div
|
||||
v-if="show"
|
||||
class="server-list-item-bill"
|
||||
:class="{
|
||||
'dot-dot-box--hide': $config.nazhua?.hideDotBG === true,
|
||||
}"
|
||||
>
|
||||
<div class="left-box">
|
||||
<div
|
||||
@ -131,6 +134,11 @@ const show = computed(() => {
|
||||
background: rgba(#000, 0.3);
|
||||
box-shadow: 0 -2px 4px rgba(#000, 0.5);
|
||||
|
||||
&.dot-dot-box--hide {
|
||||
box-shadow: none;
|
||||
border-top: 1px solid rgba(#ddd, 0.1);
|
||||
}
|
||||
|
||||
.left-box {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
<dot-dot-box
|
||||
border-radius="var(--list-item-border-radius)"
|
||||
:padding="0"
|
||||
class="server-list-item"
|
||||
:class="{
|
||||
'server-list-item--offline': info.online === -1,
|
||||
@ -7,6 +9,9 @@
|
||||
>
|
||||
<div
|
||||
class="server-info-group server-list-item-head"
|
||||
:class="{
|
||||
'dot-dot-box--hide': $config.nazhua?.hideDotBG === true,
|
||||
}"
|
||||
@click="openDetail"
|
||||
>
|
||||
<div class="server-name-group left-box">
|
||||
@ -53,7 +58,7 @@
|
||||
v-if="showBill"
|
||||
:info="info"
|
||||
/>
|
||||
</div>
|
||||
</dot-dot-box>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -107,18 +112,7 @@ const showBill = config.nazhua.hideListItemBill !== true;
|
||||
--list-item-border-radius: 12px;
|
||||
width: var(--list-item-width);
|
||||
color: #fff;
|
||||
background-image: radial-gradient(transparent 1px, rgba(#000, 0.6) 1px);
|
||||
background-size: 3px 3px;
|
||||
backdrop-filter: saturate(50%) blur(3px);
|
||||
border-radius: var(--list-item-border-radius);
|
||||
transition: 0.3s;
|
||||
box-shadow: 2px 4px 6px rgba(#000, 0.4);
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
background-color: rgba(#000, 0.8);
|
||||
background-image: none;
|
||||
backdrop-filter: none;
|
||||
}
|
||||
|
||||
.server-info-group {
|
||||
display: flex;
|
||||
@ -137,6 +131,11 @@ const showBill = config.nazhua.hideListItemBill !== true;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.dot-dot-box--hide {
|
||||
box-shadow: none;
|
||||
border-bottom: 1px solid rgba(#ddd, 0.1);
|
||||
}
|
||||
|
||||
&.server-list-item-head {
|
||||
flex-wrap: wrap;
|
||||
overflow: hidden;
|
||||
|
||||
@ -28,11 +28,23 @@ export default defineConfig({
|
||||
target: process.env.WS_HOST,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (e) => {
|
||||
if (process.env.REWRITE_WS_HOST) {
|
||||
return `/proxy?wsPath=${process.env.REWRITE_WS_HOST}`;
|
||||
}
|
||||
return e;
|
||||
},
|
||||
},
|
||||
'/api/v1/ws/server': {
|
||||
target: process.env.WS_HOST,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
rewrite: (e) => {
|
||||
if (process.env.REWRITE_WS_HOST) {
|
||||
return `/proxy?wsPath=${process.env.REWRITE_WS_HOST}`;
|
||||
}
|
||||
return e;
|
||||
},
|
||||
},
|
||||
'/nezha/': {
|
||||
target: process.env.NEZHA_HOST,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user