mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-11 22:50:42 +08:00
💥 兼容哪吒V1的数据接口
This commit is contained in:
parent
cc585221c1
commit
1c6107cb07
1
.gitignore
vendored
1
.gitignore
vendored
@ -11,6 +11,7 @@ node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
demo
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name ${DOMAIN};
|
||||
@ -7,7 +12,18 @@ server {
|
||||
proxy_pass ${NEZHA}ws;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
}
|
||||
|
||||
# 兼容哪吒V1
|
||||
location /api/v1/ws/server {
|
||||
proxy_pass ${NEZHA}api/v1/ws/server;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
|
||||
@ -16,9 +16,13 @@ window.$$nazhuaConfig = {
|
||||
// hideFilter: false, // 隐藏筛选
|
||||
// hideTag: false, // 隐藏标签
|
||||
// customCodeMap: {}, // 自定义的地图点信息
|
||||
// nezhaVersion: 'v1', // 哪吒版本
|
||||
// apiMonitorPath: '/api/v1/monitor/{id}',
|
||||
// wsPath: '/ws',
|
||||
// nezhaPath: '/nezha/',
|
||||
// nezhaV0ConfigType: 'servers', // 哪吒v0数据读取类型
|
||||
// v1ApiMonitorPath: '/api/v1/service/{id}',
|
||||
// v1WsPath: '/api/v1/ws/server',
|
||||
// v1GroupPath: '/api/v1/server-group',
|
||||
// routeMode: 'h5', // 路由模式
|
||||
};
|
||||
|
||||
@ -55,7 +55,7 @@ async function wsReconnect() {
|
||||
onMounted(async () => {
|
||||
handleSystem();
|
||||
refreshTime();
|
||||
await store.dispatch('loadServers');
|
||||
await store.dispatch('initServerInfo');
|
||||
msg.on('close', () => {
|
||||
console.log('ws closed');
|
||||
wsReconnect();
|
||||
|
||||
@ -12,10 +12,14 @@ const config = {
|
||||
},
|
||||
nazhua: {
|
||||
title: '哪吒监控',
|
||||
nezhaVersion: 'v0',
|
||||
apiMonitorPath: '/api/v1/monitor/{id}',
|
||||
wsPath: '/ws',
|
||||
nezhaPath: '/nezha/',
|
||||
nezhaV0ConfigType: 'servers',
|
||||
v1ApiMonitorPath: '/api/v1/service/{id}',
|
||||
v1WsPath: '/api/v1/ws/server',
|
||||
v1GroupPath: '/api/v1/server-group',
|
||||
// 解构载入自定义配置
|
||||
...(window.$$nazhuaConfig || {}),
|
||||
},
|
||||
|
||||
@ -2,7 +2,13 @@ import {
|
||||
createStore,
|
||||
} from 'vuex';
|
||||
import dayjs from 'dayjs';
|
||||
import loadNezhaConfig from '@/utils/load-nezha-config';
|
||||
import config from '@/config';
|
||||
import loadNezhaV0Config, {
|
||||
loadServerGroup as loadNezhaV0ServerGroup,
|
||||
} from '@/utils/load-nezha-v0-config';
|
||||
import {
|
||||
loadServerGroup as loadNezhaV1ServerGroup,
|
||||
} from '@/utils/load-nezha-v1-config';
|
||||
|
||||
import {
|
||||
msg,
|
||||
@ -10,6 +16,7 @@ import {
|
||||
|
||||
const defaultState = () => ({
|
||||
init: false,
|
||||
serverGroup: [],
|
||||
serverList: [],
|
||||
serverCount: {
|
||||
total: 0,
|
||||
@ -35,9 +42,13 @@ function handleServerCount(servers) {
|
||||
return counts;
|
||||
}
|
||||
|
||||
let firstSetServers = true;
|
||||
const store = createStore({
|
||||
state: defaultState(),
|
||||
mutations: {
|
||||
SET_SERVER_GROUP(state, serverGroup) {
|
||||
state.serverGroup = serverGroup;
|
||||
},
|
||||
SET_SERVERS(state, servers) {
|
||||
const newServers = [...servers];
|
||||
newServers.sort((a, b) => b.DisplayIndex - a.DisplayIndex);
|
||||
@ -58,8 +69,6 @@ const store = createStore({
|
||||
};
|
||||
if (oldItem?.PublicNote) {
|
||||
serverItem.PublicNote = oldItem.PublicNote;
|
||||
} else {
|
||||
serverItem.PublicNote = {};
|
||||
}
|
||||
return serverItem;
|
||||
});
|
||||
@ -74,8 +83,20 @@ const store = createStore({
|
||||
/**
|
||||
* 加载服务器列表
|
||||
*/
|
||||
async loadServers({ commit }) {
|
||||
const serverResult = await loadNezhaConfig();
|
||||
async initServerInfo({ commit }) {
|
||||
firstSetServers = true;
|
||||
// 如果是v1版本的话,加载v1版本的数据
|
||||
if (config.nazhua.nezhaVersion === 'v1') {
|
||||
loadNezhaV1ServerGroup().then((res) => {
|
||||
if (res) {
|
||||
commit('SET_SERVER_GROUP', res);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// 如果是v0版本的话,加载v0版本的数据
|
||||
// 加载初始化的服务器列表,需要其中的公开备注字段
|
||||
const serverResult = await loadNezhaV0Config();
|
||||
if (!serverResult) {
|
||||
console.error('load server config failed');
|
||||
return;
|
||||
@ -87,6 +108,11 @@ const store = createStore({
|
||||
};
|
||||
return item;
|
||||
}) || [];
|
||||
const res = loadNezhaV0ServerGroup(servers);
|
||||
if (res) {
|
||||
commit('SET_SERVER_GROUP', res);
|
||||
}
|
||||
firstSetServers = false;
|
||||
commit('SET_SERVERS', servers);
|
||||
},
|
||||
/**
|
||||
@ -104,7 +130,12 @@ const store = createStore({
|
||||
};
|
||||
return item;
|
||||
}) || [];
|
||||
commit('UPDATE_SERVERS', servers);
|
||||
if (firstSetServers) {
|
||||
firstSetServers = false;
|
||||
commit('SET_SERVERS', servers);
|
||||
} else {
|
||||
commit('UPDATE_SERVERS', servers);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@ -38,3 +38,30 @@ export default async () => fetch(config.nazhua.nezhaPath).then((res) => res.text
|
||||
}
|
||||
return null;
|
||||
}).catch(() => null);
|
||||
|
||||
/**
|
||||
* 获取标签列表
|
||||
*/
|
||||
export const loadServerGroup = (services) => {
|
||||
const tagMap = {};
|
||||
services.forEach((i) => {
|
||||
if (i.Tag) {
|
||||
if (!tagMap[i.Tag]) {
|
||||
tagMap[i.Tag] = [];
|
||||
}
|
||||
tagMap[i.Tag].push(i);
|
||||
}
|
||||
});
|
||||
const tagList = [];
|
||||
Object.entries(tagMap).forEach(([tag, serviceIds]) => {
|
||||
tagList.push({
|
||||
name: tag,
|
||||
count: serviceIds.length,
|
||||
servers: serviceIds,
|
||||
group: {
|
||||
name: tag,
|
||||
},
|
||||
});
|
||||
});
|
||||
return tagList;
|
||||
};
|
||||
138
src/utils/load-nezha-v1-config.js
Normal file
138
src/utils/load-nezha-v1-config.js
Normal file
@ -0,0 +1,138 @@
|
||||
/**
|
||||
* V1版数据加载
|
||||
*/
|
||||
import store from '@/store';
|
||||
import config from '@/config';
|
||||
import request from '@/utils/request';
|
||||
import { Mapping } from '@/utils/object-mapping';
|
||||
|
||||
/**
|
||||
* 字段映射
|
||||
*/
|
||||
export const SERVER_FIELD_MAPS = {
|
||||
ID: 'id',
|
||||
CreatedAt: undefined,
|
||||
UpdatedAt: undefined,
|
||||
DeletedAt: undefined,
|
||||
Name: 'name',
|
||||
Tag: '_$function|queryGroup|id',
|
||||
DisplayIndex: 'display_index',
|
||||
HideForGuest: undefined,
|
||||
EnableDDNS: undefined,
|
||||
Host: '_$mapping|HOST_FIELD_MAPS',
|
||||
State: '_$mapping|STATE_FIELD_MAPS',
|
||||
LastActive: 'last_active',
|
||||
};
|
||||
export const HOST_FIELD_MAPS = {
|
||||
Platform: 'host.platform',
|
||||
PlatformVersion: 'host.platform_version',
|
||||
CPU: 'host.cpu',
|
||||
MemTotal: 'host.mem_total',
|
||||
DiskTotal: 'host.disk_total',
|
||||
SwapTotal: 'host.swap_total',
|
||||
Arch: 'host.arch',
|
||||
Virtualization: 'host.virtualization',
|
||||
BootTime: 'host.boot_time',
|
||||
CountryCode: 'country_code',
|
||||
Version: 'host.version',
|
||||
GPU: 'host.gpu',
|
||||
};
|
||||
export const STATE_FIELD_MAPS = {
|
||||
CPU: 'state.cpu',
|
||||
MemUsed: 'state.mem_used',
|
||||
SwapUsed: 'state.swap_used',
|
||||
DiskUsed: 'state.disk_used',
|
||||
NetInTransfer: 'state.net_in_transfer',
|
||||
NetOutTransfer: 'state.net_out_transfer',
|
||||
NetInSpeed: 'state.net_in_speed',
|
||||
NetOutSpeed: 'state.net_out_speed',
|
||||
Uptime: 'state.uptime',
|
||||
Load1: 'state.load_1',
|
||||
Load5: 'state.load_5',
|
||||
Load15: 'state.load_15',
|
||||
TcpConnCount: 'state.tcp_conn_count',
|
||||
UdpConnCount: 'state.udp_conn_count',
|
||||
ProcessCount: 'state.process_count',
|
||||
Temperatures: 'state.temperatures',
|
||||
GPU: 'state.gpu',
|
||||
};
|
||||
|
||||
/**
|
||||
* 魔法方法
|
||||
*/
|
||||
const magics = {
|
||||
HOST_FIELD_MAPS,
|
||||
STATE_FIELD_MAPS,
|
||||
queryGroup: (id) => {
|
||||
const groupItem = store.state.serverGroup?.find?.((i) => {
|
||||
if (i.servers) {
|
||||
return i.servers.includes(id);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return groupItem?.name;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理V1版数据
|
||||
* @param {Object} v1Data V1版数据
|
||||
* @return {Object} V0版数据
|
||||
*/
|
||||
export const handelV1toV0 = (v1Data) => {
|
||||
const v0Data = {};
|
||||
Object.keys(SERVER_FIELD_MAPS).forEach((key) => {
|
||||
if (SERVER_FIELD_MAPS[key] === undefined) {
|
||||
return;
|
||||
}
|
||||
if (SERVER_FIELD_MAPS[key].includes('_$')) {
|
||||
const $magic = SERVER_FIELD_MAPS[key].split('|');
|
||||
switch ($magic[0]) {
|
||||
case '_$function':
|
||||
if ($magic.length >= 3 && magics[$magic[1]]) {
|
||||
v0Data[key] = magics[$magic[1]](
|
||||
Mapping.mapping(v1Data, $magic[2]),
|
||||
);
|
||||
} else {
|
||||
v0Data[key] = undefined;
|
||||
}
|
||||
break;
|
||||
case '_$mapping':
|
||||
v0Data[key] = Mapping.each(magics[$magic[1]], v1Data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
v0Data[key] = Mapping.mapping(v1Data, SERVER_FIELD_MAPS[key]);
|
||||
});
|
||||
if (v1Data.public_note) {
|
||||
try {
|
||||
v0Data.PublicNote = JSON.parse(v1Data.public_note);
|
||||
} catch (e) {
|
||||
v1Data.PublicNote = null;
|
||||
}
|
||||
} else {
|
||||
v1Data.PublicNote = null;
|
||||
}
|
||||
return v0Data;
|
||||
};
|
||||
|
||||
export const loadServerGroup = async () => request({
|
||||
url: config.nazhua.v1GroupPath,
|
||||
type: 'GET',
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
const list = res.data?.data || [];
|
||||
return list.map((i) => {
|
||||
const item = {
|
||||
...i,
|
||||
name: i?.group?.name,
|
||||
count: i?.servers?.length,
|
||||
};
|
||||
return item;
|
||||
});
|
||||
}
|
||||
return null;
|
||||
}).catch(() => null);
|
||||
99
src/utils/object-mapping.js
Normal file
99
src/utils/object-mapping.js
Normal file
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* 对象映射封装
|
||||
*/
|
||||
class Mapping {
|
||||
/**
|
||||
* 字符串映射对象
|
||||
*
|
||||
* @param {Record<string, any>} obj 查找的对象
|
||||
* @param {string} key 查找的属性
|
||||
*
|
||||
* @return {any}
|
||||
*/
|
||||
static mapping(obj, key) {
|
||||
// 检查 obj 是否为对象,如果不是,返回 undefined
|
||||
if (!obj || typeof obj !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
// 检查 key 是否为字符串,如果不是,返回 undefined
|
||||
if (typeof key !== 'string') {
|
||||
return undefined;
|
||||
}
|
||||
// 检查 key 是否包含非法字符,如果包含,返回 undefined
|
||||
if (key.includes('..') || key.startsWith('.') || key.endsWith('.')) {
|
||||
return undefined;
|
||||
}
|
||||
// 如果 key 包含 '.',使用 reduce 方法递归获取嵌套属性值
|
||||
if (key.includes('.')) {
|
||||
return key.split('.').reduce((val, k) => (val !== undefined ? Mapping.get(val, k) : undefined), obj);
|
||||
}
|
||||
// 如果 key 不包含 '.',直接获取属性值
|
||||
return Mapping.get(obj, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据
|
||||
* 支持处理数组指针
|
||||
* @param {Record<string, any> | any[]} obj 属性对象
|
||||
* @param {string} key 属性名称
|
||||
* @return {any}
|
||||
*/
|
||||
static get(obj, key) {
|
||||
if (!obj || typeof obj !== 'object' || !key) {
|
||||
return undefined;
|
||||
}
|
||||
const indexMatch = key.match(/\[(\d+)\]/);
|
||||
if (indexMatch) {
|
||||
const [fullMatch, indexStr] = indexMatch;
|
||||
const index = Number(indexStr);
|
||||
const matchIndex = key.indexOf(fullMatch);
|
||||
if (matchIndex === 0) {
|
||||
if (Array.isArray(obj) && index < obj.length) {
|
||||
const val = obj[index];
|
||||
const restKey = key.slice(fullMatch.length);
|
||||
return restKey ? Mapping.get(val, restKey) : val;
|
||||
}
|
||||
} else {
|
||||
const pre = key.slice(0, matchIndex);
|
||||
const list = obj[pre];
|
||||
if (Array.isArray(list) && index < list.length) {
|
||||
const val = list[index];
|
||||
const restKey = key.slice(matchIndex + fullMatch.length);
|
||||
return restKey ? Mapping.get(val, restKey) : val;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
return obj[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据根据key的映射进行组装
|
||||
*
|
||||
* @param {KeyMap} keys 映射对象
|
||||
* @param {Record<string, unknown>} data 数据对象
|
||||
*
|
||||
* @return {Record<string, unknown>}
|
||||
*/
|
||||
static each(keys, data) {
|
||||
// 检查 keys 是否为对象,如果不是,返回 undefined
|
||||
if (!keys || typeof keys !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
// 检查 data 是否为对象,如果不是,返回 undefined
|
||||
if (!data || typeof data !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
return Object.entries(keys).reduce((acc, [key, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
acc[key] = Mapping.mapping(data, value);
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
}
|
||||
const { mapping } = Mapping;
|
||||
|
||||
export { Mapping, mapping };
|
||||
|
||||
export default mapping;
|
||||
@ -1,39 +1,21 @@
|
||||
import axios from 'axios';
|
||||
import uuid from '@/utils/uuid';
|
||||
import validate from '@/utils/validate';
|
||||
|
||||
import config from '@/config';
|
||||
import CustomError from './custom-error';
|
||||
|
||||
const {
|
||||
codeField,
|
||||
dataField,
|
||||
msgField,
|
||||
okCode,
|
||||
limit = 10,
|
||||
} = config.request;
|
||||
const limit = 10;
|
||||
|
||||
const requestTagMap = {};
|
||||
|
||||
/**
|
||||
* axios请求
|
||||
* @param {object} options 请求参数
|
||||
* @param {boolean} noFormat 不进行返回数据的格式化处理 网络状态200即为成功
|
||||
* @return {Promise}
|
||||
*/
|
||||
async function axiosRequest(options, noFormat) {
|
||||
async function axiosRequest(options) {
|
||||
return axios(options).then((res) => {
|
||||
if (res.status === 200) {
|
||||
if (noFormat) {
|
||||
return res;
|
||||
}
|
||||
if (validate.isSet(res.data[codeField]) && `${res.data[codeField]}` === `${okCode}`) {
|
||||
return res.data[dataField];
|
||||
}
|
||||
if (typeof res.data[codeField] !== 'undefined') {
|
||||
throw new CustomError(res.data[msgField], res.data[codeField]);
|
||||
}
|
||||
throw new CustomError('服务器返回内容不规范', -99);
|
||||
return res;
|
||||
}
|
||||
throw new CustomError(`网络错误${res.status}`, res.status);
|
||||
});
|
||||
@ -69,7 +51,6 @@ class NetworkRequest {
|
||||
* @param {string} type 请求的Method
|
||||
* @param {object} headers Header请求参数
|
||||
* @param {object} data 请求参数
|
||||
* @param {boolean} noFormat 不进行返回数据的格式化处理 网络状态200即为成功
|
||||
* @param {boolean} defaultContentType 默认的请求方式
|
||||
* @param {Boolean} priority 优先调用请求
|
||||
*
|
||||
@ -85,7 +66,6 @@ class NetworkRequest {
|
||||
type,
|
||||
headers,
|
||||
data,
|
||||
noFormat = false,
|
||||
defaultContentType = true,
|
||||
requestTag = undefined,
|
||||
responseType,
|
||||
@ -100,9 +80,7 @@ class NetworkRequest {
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const defaultHeaders = {
|
||||
...config.request.headers,
|
||||
};
|
||||
const defaultHeaders = {};
|
||||
if (defaultContentType === false) {
|
||||
if (NetworkRequest.FormRequest(defaultHeaders)) {
|
||||
defaultHeaders['content-type'] = 'application/json';
|
||||
@ -122,7 +100,6 @@ class NetworkRequest {
|
||||
signal: abortController?.signal ?? undefined,
|
||||
responseType,
|
||||
},
|
||||
noFormat,
|
||||
(res) => {
|
||||
resolve(res);
|
||||
},
|
||||
@ -153,13 +130,13 @@ class NetworkRequest {
|
||||
if (this.tasks.length === 0) {
|
||||
return;
|
||||
}
|
||||
const [options, onFormat, success, fail, tag] = this.tasks.pop();
|
||||
const [options, success, fail, tag] = this.tasks.pop();
|
||||
// 请求未执行已被中止
|
||||
if (options?.signal?.aborted) {
|
||||
this.overTask();
|
||||
return;
|
||||
}
|
||||
requestTagMap[tag] = axiosRequest(options, onFormat);
|
||||
requestTagMap[tag] = axiosRequest(options);
|
||||
requestTagMap[tag].finally(() => {
|
||||
this.overTask();
|
||||
// 一秒内请求不重复
|
||||
|
||||
@ -131,10 +131,13 @@ function switchPeakShaving() {
|
||||
|
||||
async function loadMonitor() {
|
||||
await request({
|
||||
url: config.nazhua.apiMonitorPath.replace('{id}', props.info.ID),
|
||||
url: (
|
||||
config.nazhua.nezhaVersion === 'v1' ? config.nazhua.v1ApiMonitorPath : config.nazhua.apiMonitorPath
|
||||
).replace('{id}', props.info.ID),
|
||||
}).then((res) => {
|
||||
if (Array.isArray(res)) {
|
||||
monitorData.value = res;
|
||||
const list = config.nazhua.nezhaVersion === 'v1' ? res.data?.data : res.data?.result;
|
||||
if (Array.isArray(list)) {
|
||||
monitorData.value = list;
|
||||
}
|
||||
}).catch((err) => {
|
||||
console.error(err);
|
||||
|
||||
@ -45,8 +45,10 @@
|
||||
>
|
||||
<span class="text">
|
||||
<span class="text-item value-text">{{ billAndPlan.billing.value }}</span>
|
||||
<span class="text-item">/</span>
|
||||
<span class="text-item label-text">{{ billAndPlan.billing.cycleLabel }}</span>
|
||||
<template v-if="!billAndPlan.billing.isFree">
|
||||
<span class="text-item">/</span>
|
||||
<span class="text-item label-text">{{ billAndPlan.billing.cycleLabel }}</span>
|
||||
</template>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
|
||||
@ -64,6 +64,7 @@ export default (params) => {
|
||||
}
|
||||
}
|
||||
if (validate.isSet(billingDataMod?.amount)) {
|
||||
let isFree = false;
|
||||
let amountValue = billingDataMod.amount;
|
||||
let label;
|
||||
if (billingDataMod.amount.toString() === '-1') {
|
||||
@ -71,6 +72,7 @@ export default (params) => {
|
||||
label = `每${cycleLabel}`;
|
||||
} else if (billingDataMod.amount.toString() === '0') {
|
||||
amountValue = config.nazhua.freeAmount || '免费';
|
||||
isFree = true;
|
||||
} else {
|
||||
label = `${cycleLabel}付`;
|
||||
}
|
||||
@ -79,6 +81,7 @@ export default (params) => {
|
||||
value: amountValue,
|
||||
cycleLabel,
|
||||
months,
|
||||
isFree,
|
||||
};
|
||||
}
|
||||
// 剩余时间
|
||||
|
||||
@ -63,12 +63,12 @@ export default (params) => {
|
||||
case 'cpu':
|
||||
return {
|
||||
type: 'cpu',
|
||||
used: (props.info.State.CPU).toFixed(1) * 1,
|
||||
used: (props.info.State?.CPU || 0).toFixed(1) * 1,
|
||||
colors: {
|
||||
used: '#0088ff',
|
||||
total: 'rgba(255, 255, 255, 0.2)',
|
||||
},
|
||||
valText: `${(props.info.State.CPU).toFixed(1) * 1}%`,
|
||||
valText: `${(props.info.State?.CPU || 0).toFixed(1) * 1}%`,
|
||||
label: 'CPU',
|
||||
content: {
|
||||
default: cpuInfo.value?.core,
|
||||
|
||||
@ -87,35 +87,10 @@ const serverList = computed(() => store.state.serverList);
|
||||
// 服务器总数
|
||||
const serverCount = computed(() => store.state.serverCount);
|
||||
|
||||
/**
|
||||
* 解构数据
|
||||
*/
|
||||
const serverListData = computed(() => {
|
||||
const tagMap = {};
|
||||
serverList.value.forEach((i) => {
|
||||
if (i.Tag) {
|
||||
if (!tagMap[i.Tag]) {
|
||||
tagMap[i.Tag] = 0;
|
||||
}
|
||||
tagMap[i.Tag] += 1;
|
||||
}
|
||||
});
|
||||
const tags = [];
|
||||
Object.entries(tagMap).forEach(([tag, count]) => {
|
||||
tags.push({
|
||||
tag,
|
||||
count,
|
||||
});
|
||||
});
|
||||
return {
|
||||
tags,
|
||||
};
|
||||
});
|
||||
|
||||
const tagOptions = computed(() => (serverListData.value?.tags || []).map((i) => ({
|
||||
const tagOptions = computed(() => store.state.serverGroup.map((i) => ({
|
||||
key: uuid(),
|
||||
label: i.tag,
|
||||
value: i.tag,
|
||||
label: i.name,
|
||||
value: i.name,
|
||||
})));
|
||||
|
||||
const onlineOptions = computed(() => {
|
||||
|
||||
@ -1,10 +1,20 @@
|
||||
import config from '@/config';
|
||||
import MessageSubscribe from '@/utils/subscribe';
|
||||
import {
|
||||
handelV1toV0,
|
||||
} from '@/utils/load-nezha-v1-config';
|
||||
import WSService from './service';
|
||||
|
||||
function getWsApiPath() {
|
||||
if (config.nazhua.nezhaVersion === 'v1') {
|
||||
return config.nazhua.v1WsPath;
|
||||
}
|
||||
return config.nazhua.wsPath;
|
||||
}
|
||||
|
||||
const msg = new MessageSubscribe();
|
||||
const wsService = new WSService({
|
||||
wsUrl: config?.nazhua?.wsPath,
|
||||
wsUrl: getWsApiPath(),
|
||||
onConnect: () => {
|
||||
msg.emit('connect');
|
||||
},
|
||||
@ -16,7 +26,17 @@ const wsService = new WSService({
|
||||
},
|
||||
onMessage: (data) => {
|
||||
if (data?.now) {
|
||||
msg.emit('servers', data);
|
||||
if (config.nazhua.nezhaVersion === 'v1') {
|
||||
msg.emit('servers', {
|
||||
now: data.now,
|
||||
servers: data?.servers?.map?.((server) => {
|
||||
const item = handelV1toV0(server);
|
||||
return item;
|
||||
}) || [],
|
||||
});
|
||||
} else {
|
||||
msg.emit('servers', data);
|
||||
}
|
||||
} else {
|
||||
msg.emit('message', data);
|
||||
}
|
||||
|
||||
@ -29,6 +29,11 @@ export default defineConfig({
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
'/api/v1/ws/server': {
|
||||
target: process.env.WS_HOST,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
},
|
||||
'/nezha/': {
|
||||
target: process.env.NEZHA_HOST,
|
||||
changeOrigin: true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user