🚀 0.4.3

拆分点阵背景图为独立组件,支持显示控制;
config挂上reactive,支持动态响应,未来更优雅的支持配置;
执行setting的custom_code;
This commit is contained in:
hi2hi 2024-12-06 16:34:31 +00:00
parent 70dbd77f19
commit 4e2ff5b84e
14 changed files with 212 additions and 90 deletions

View File

@ -1,6 +1,6 @@
{
"name": "nazhua",
"version": "0.4.2",
"version": "0.4.3",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -16,6 +16,7 @@ window.$$nazhuaConfig = {
// hideListItemBill: false, // 隐藏列表项的账单信息
// hideFilter: false, // 隐藏筛选
// hideTag: false, // 隐藏标签
// hideDotBG: true, // 隐藏框框里面的点点背景
// customCodeMap: {}, // 自定义的地图点信息
// nezhaVersion: 'v1', // 哪吒版本
// apiMonitorPath: '/api/v1/monitor/{id}',

View 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>

View File

@ -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) => {

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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 {

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}

View File

@ -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;

View File

@ -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,