mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-19 10:40:43 +08:00
Compare commits
No commits in common. "582b3670880478f3a8282e5e1ea2b8d9f9178a6e" and "f8cef00bfd71d5cf1ef6071f5d986b0392d6b58b" have entirely different histories.
582b367088
...
f8cef00bfd
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nazhua",
|
"name": "nazhua",
|
||||||
"version": "0.4.22",
|
"version": "0.4.20",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@ -3,7 +3,6 @@ window.$$nazhuaConfig = {
|
|||||||
// freeAmount: '白嫖', // 免费服务的费用名称
|
// freeAmount: '白嫖', // 免费服务的费用名称
|
||||||
// infinityCycle: '长期有效', // 无限周期名称
|
// infinityCycle: '长期有效', // 无限周期名称
|
||||||
// buyBtnText: '购买', // 购买按钮文案
|
// buyBtnText: '购买', // 购买按钮文案
|
||||||
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式移动端自动切换至card
|
|
||||||
// listServerStatusType: 'progress', // 服务器状态类型--列表
|
// listServerStatusType: 'progress', // 服务器状态类型--列表
|
||||||
// listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
// listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
||||||
// detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
// detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
||||||
|
|||||||
14
readme.md
14
readme.md
@ -5,7 +5,7 @@
|
|||||||
根据不同场景,可以选择是否打包带入或者是否加载这个字体。
|
根据不同场景,可以选择是否打包带入或者是否加载这个字体。
|
||||||
|
|
||||||
## 劝退指南 用前必读
|
## 劝退指南 用前必读
|
||||||
1. 本主题是基于哪吒监控v0版本构建的,~~不确定能否完美v1版本~~。*v0.4.3的版本已适配*
|
1. 本主题是基于哪吒监控v0版本构建的,不确定能否完美v1版本。*20241206的版本已适配*
|
||||||
2. 本主题是一个纯前端项目,需要解决跨域问题,通常需要一个nginx或者caddy反代请求解决跨域问题。
|
2. 本主题是一个纯前端项目,需要解决跨域问题,通常需要一个nginx或者caddy反代请求解决跨域问题。
|
||||||
3. 我不会提供任何技术支持,如果你有问题,可以提issue,但是我不保证会回答,可能询问GPT会更快。
|
3. 我不会提供任何技术支持,如果你有问题,可以提issue,但是我不保证会回答,可能询问GPT会更快。
|
||||||
|
|
||||||
@ -15,9 +15,7 @@
|
|||||||
默认的数据是基于V0
|
默认的数据是基于V0
|
||||||
### Release版本的nazhua
|
### Release版本的nazhua
|
||||||
V1下载最新版本[Releases](https://github.com/hi2shark/nazhua/releases)的`dist.zip`;
|
V1下载最新版本[Releases](https://github.com/hi2shark/nazhua/releases)的`dist.zip`;
|
||||||
V0下载最新版本[Releases](https://github.com/hi2shark/nazhua/releases)的`v0-dist.zip`;
|
V0下载最新版本[Releases](https://github.com/hi2shark/nazhua/releases)的`v0-{版本}-all.zip`或`v0-{版本}-cdn-{CDN供应方}.zip`;
|
||||||
`v{版本}-all.zip`是包含字体的全量包。
|
|
||||||
`v{版本}-cdn-{CDN供应方}.zip`是公共资源使用CDN引用的版本。
|
|
||||||
|
|
||||||
## 关于点阵地图
|
## 关于点阵地图
|
||||||
点阵地图是一个失真的地图,地图边际与城市位置都不是真实的经纬度坐标,因此无法通过经纬度来定位城市。
|
点阵地图是一个失真的地图,地图边际与城市位置都不是真实的经纬度坐标,因此无法通过经纬度来定位城市。
|
||||||
@ -183,13 +181,11 @@ server {
|
|||||||
window.$$nazhuaConfig = {
|
window.$$nazhuaConfig = {
|
||||||
title: '哪吒监控', // 网站标题
|
title: '哪吒监控', // 网站标题
|
||||||
freeAmount: '白嫖', // 免费服务的费用名称
|
freeAmount: '白嫖', // 免费服务的费用名称
|
||||||
infinityCycle: '长期有效', // 无限周期名称
|
infinityCycle: '无限', // 无限周期名称
|
||||||
buyBtnText: '购买', // 购买按钮文案
|
buyBtnText: '购买', // 购买按钮文案
|
||||||
listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式目前不兼容移动端
|
|
||||||
listServerStatusType: 'progress', // 服务器状态类型--列表
|
listServerStatusType: 'progress', // 服务器状态类型--列表
|
||||||
listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
|
||||||
detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
detailServerStatusType: 'progress', // 服务器状态类型--详情页
|
||||||
serverStatusLinear: true, // 服务器状态渐变线性显示
|
|
||||||
disableSarasaTermSC: false, // 禁用Sarasa Term SC字体
|
disableSarasaTermSC: false, // 禁用Sarasa Term SC字体
|
||||||
hideWorldMap: false, // 隐藏地图
|
hideWorldMap: false, // 隐藏地图
|
||||||
hideHomeWorldMap: false, // 隐藏首页地图
|
hideHomeWorldMap: false, // 隐藏首页地图
|
||||||
@ -201,7 +197,7 @@ window.$$nazhuaConfig = {
|
|||||||
hideListItemBill: false, // 隐藏列表项的账单信息
|
hideListItemBill: false, // 隐藏列表项的账单信息
|
||||||
hideFilter: false, // 隐藏筛选
|
hideFilter: false, // 隐藏筛选
|
||||||
hideTag: false, // 隐藏标签
|
hideTag: false, // 隐藏标签
|
||||||
hideDotBG: true, // 隐藏框框里面的点点背景
|
hideDotBG: false, // 隐藏框框里面的点点背景
|
||||||
monitorRefreshTime: 10, // 监控刷新时间间隔,单位s(秒), 0为不刷新,为保证不频繁请求源站,最低生效值为10s
|
monitorRefreshTime: 10, // 监控刷新时间间隔,单位s(秒), 0为不刷新,为保证不频繁请求源站,最低生效值为10s
|
||||||
filterGPUKeywords: ['Virtual Display'], // 如果GPU名称中包含这些关键字,则过滤掉
|
filterGPUKeywords: ['Virtual Display'], // 如果GPU名称中包含这些关键字,则过滤掉
|
||||||
customCodeMap: {}, // 自定义的地图点信息
|
customCodeMap: {}, // 自定义的地图点信息
|
||||||
@ -216,7 +212,7 @@ window.$$nazhuaConfig = {
|
|||||||
v1ApiSettingPath: '/api/v1/setting',
|
v1ApiSettingPath: '/api/v1/setting',
|
||||||
v1ApiProfilePath: '/api/v1/profile',
|
v1ApiProfilePath: '/api/v1/profile',
|
||||||
v1DashboardUrl: '/dashboard', // v1版本控制台地址
|
v1DashboardUrl: '/dashboard', // v1版本控制台地址
|
||||||
v1HideNezhaDashboardBtn: true, // v1版本导航栏控制台入口/登录按钮 在nezhaVersion为v1时有效
|
v1HideNezhaDashboardBtn: false, // v1版本导航栏控制台入口/登录按钮 在nezhaVersion为v1时有效
|
||||||
routeMode: 'h5', // 路由模式
|
routeMode: 'h5', // 路由模式
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|||||||
@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
--list-item-price-color: #eee;
|
--list-item-price-color: #eee;
|
||||||
--list-item-buy-link-color: #ffc300;
|
--list-item-buy-link-color: #ffc300;
|
||||||
--list-item-buy-link-color-hover: #ff9900;
|
|
||||||
--public-note-tag-color: #ddd;
|
--public-note-tag-color: #ddd;
|
||||||
--public-note-tag-bg: linear-gradient(125deg, #8f94fb, #4e54c8);
|
--public-note-tag-bg: linear-gradient(125deg, #8f94fb, #4e54c8);
|
||||||
|
|
||||||
|
|||||||
@ -21,7 +21,6 @@ const defaultState = () => ({
|
|||||||
serverTime: 0,
|
serverTime: 0,
|
||||||
serverGroup: [],
|
serverGroup: [],
|
||||||
serverList: [],
|
serverList: [],
|
||||||
serverListColumnWidths: {},
|
|
||||||
serverCount: {
|
serverCount: {
|
||||||
total: 0,
|
total: 0,
|
||||||
online: 0,
|
online: 0,
|
||||||
@ -93,9 +92,6 @@ const store = createStore({
|
|||||||
SET_SETTING(state, setting) {
|
SET_SETTING(state, setting) {
|
||||||
state.setting = setting;
|
state.setting = setting;
|
||||||
},
|
},
|
||||||
SET_SERVER_LIST_COLUMN_WIDTHS(state, widths) {
|
|
||||||
state.serverListColumnWidths = widths;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
/**
|
/**
|
||||||
@ -188,33 +184,6 @@ const store = createStore({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
/**
|
|
||||||
* 设置服务器列表行宽度
|
|
||||||
*/
|
|
||||||
setServerListColumnWidths({
|
|
||||||
commit,
|
|
||||||
state,
|
|
||||||
}, data) {
|
|
||||||
const newWidths = {
|
|
||||||
...state.serverListColumnWidths,
|
|
||||||
...data,
|
|
||||||
};
|
|
||||||
commit('SET_SERVER_LIST_COLUMN_WIDTHS', newWidths);
|
|
||||||
},
|
|
||||||
setServerListColumnWidth({
|
|
||||||
commit,
|
|
||||||
state,
|
|
||||||
}, data) {
|
|
||||||
const newWidths = {
|
|
||||||
...state.serverListColumnWidths,
|
|
||||||
};
|
|
||||||
if (newWidths[data.prop]) {
|
|
||||||
newWidths[data.prop] = Math.max(newWidths[data.prop], data.width);
|
|
||||||
} else {
|
|
||||||
newWidths[data.prop] = data.width;
|
|
||||||
}
|
|
||||||
commit('SET_SERVER_LIST_COLUMN_WIDTHS', newWidths);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -1,211 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="list-column"
|
|
||||||
:class="`list-column--${prop}`"
|
|
||||||
:style="columnStyle"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
ref="columnContentRef"
|
|
||||||
class="list-column-content"
|
|
||||||
>
|
|
||||||
<span class="item-label">{{ label }}</span>
|
|
||||||
<div class="item-content">
|
|
||||||
<template v-if="slotContent">
|
|
||||||
<slot />
|
|
||||||
</template>
|
|
||||||
<template v-if="slotValue">
|
|
||||||
<span class="item-text item-value">
|
|
||||||
<slot name="value" />
|
|
||||||
</span>
|
|
||||||
<span class="item-text item-unit">
|
|
||||||
<slot name="unit" />
|
|
||||||
</span>
|
|
||||||
</template>
|
|
||||||
<template v-else>
|
|
||||||
<span class="item-text item-value">{{ value }}</span>
|
|
||||||
<span class="item-text item-unit">{{ unit }}</span>
|
|
||||||
</template>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 服务器信息列表列
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
computed,
|
|
||||||
ref,
|
|
||||||
onMounted,
|
|
||||||
onBeforeUnmount,
|
|
||||||
} from 'vue';
|
|
||||||
import {
|
|
||||||
useStore,
|
|
||||||
} from 'vuex';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
prop: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
unit: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
width: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: null,
|
|
||||||
},
|
|
||||||
slotContent: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
slotValue: {
|
|
||||||
type: [String, Boolean],
|
|
||||||
default: false,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const store = useStore();
|
|
||||||
|
|
||||||
const columnContentRef = ref(null);
|
|
||||||
let resizeObserver = null;
|
|
||||||
|
|
||||||
const columnWidth = computed(() => store.state?.serverListColumnWidths?.[props.prop]);
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
if (columnContentRef.value) {
|
|
||||||
resizeObserver = new ResizeObserver((entries) => {
|
|
||||||
entries.forEach((entry) => {
|
|
||||||
let { width } = entry.contentRect;
|
|
||||||
width = Math.ceil(width);
|
|
||||||
store.dispatch('setServerListColumnWidth', {
|
|
||||||
prop: props.prop,
|
|
||||||
width: width > 40 ? width : 40,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
resizeObserver.observe(columnContentRef.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (resizeObserver) {
|
|
||||||
resizeObserver.disconnect();
|
|
||||||
resizeObserver = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const columnStyle = computed(() => {
|
|
||||||
const style = {};
|
|
||||||
if (props.width) {
|
|
||||||
const width = parseInt(props.width, 10);
|
|
||||||
if (Number.isNaN(width) === false) {
|
|
||||||
style.width = `${width}px`;
|
|
||||||
}
|
|
||||||
} else if (columnWidth.value > 0) {
|
|
||||||
style.width = `${columnWidth.value}px`;
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.list-column {
|
|
||||||
--list-column-label-height: 16px;
|
|
||||||
--list-column-value-height: 24px;
|
|
||||||
position: relative;
|
|
||||||
width: auto;
|
|
||||||
height: calc(var(--list-column-label-height) + var(--list-column-value-height) + 10px);
|
|
||||||
|
|
||||||
.list-column-content {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: max-content;
|
|
||||||
height: var(--list-item-height);
|
|
||||||
|
|
||||||
.item-label {
|
|
||||||
padding-top: 6px; // 视觉修正
|
|
||||||
line-height: var(--list-column-label-height);
|
|
||||||
font-size: 12px;
|
|
||||||
color: #bbb;
|
|
||||||
}
|
|
||||||
.item-content {
|
|
||||||
line-height: var(--list-column-value-height);
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--duration {
|
|
||||||
.item-value {
|
|
||||||
color: var(--duration-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--load {
|
|
||||||
.item-value {
|
|
||||||
color: var(--load-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--transfer {
|
|
||||||
.item-value {
|
|
||||||
color: var(--transfer-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--inTransfer {
|
|
||||||
.item-value {
|
|
||||||
color: var(--transfer-in-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--outTransfer {
|
|
||||||
.item-value {
|
|
||||||
color: var(--transfer-out-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--inSpeed {
|
|
||||||
.item-value {
|
|
||||||
color: var(--net-speed-in-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--outSpeed {
|
|
||||||
.item-value {
|
|
||||||
color: var(--net-speed-out-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--remaining-time {
|
|
||||||
.value-text {
|
|
||||||
color: #74dbef;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&--billing {
|
|
||||||
.value-text {
|
|
||||||
color: var(--list-item-price-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,83 +0,0 @@
|
|||||||
<template>
|
|
||||||
<server-list-column
|
|
||||||
v-if="extraFields?.remainingTime"
|
|
||||||
prop="remaining-time"
|
|
||||||
label="剩余"
|
|
||||||
:value="billAndPlan?.remainingTime?.value || '-'"
|
|
||||||
/>
|
|
||||||
<server-list-column
|
|
||||||
v-if="extraFields?.billing"
|
|
||||||
prop="billing"
|
|
||||||
label="费用"
|
|
||||||
:value="billAndPlan?.billing?.value || '-'"
|
|
||||||
/>
|
|
||||||
<server-list-column
|
|
||||||
v-if="extraFields?.orderLink"
|
|
||||||
prop="order-link"
|
|
||||||
label="链接"
|
|
||||||
:slot-content="true"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
v-if="showBuyBtn"
|
|
||||||
class="order-link"
|
|
||||||
@click="toBuy"
|
|
||||||
>
|
|
||||||
{{ buyBtnText }}
|
|
||||||
</span>
|
|
||||||
<span v-else>-</span>
|
|
||||||
</server-list-column>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 套餐信息
|
|
||||||
*/
|
|
||||||
import {
|
|
||||||
inject,
|
|
||||||
computed,
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
import handleServerBillAndPlan from '@/views/composable/server-bill-and-plan';
|
|
||||||
|
|
||||||
import ServerListColumn from './server-list-column.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const filterServerList = inject('filterServerList', {
|
|
||||||
value: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
const extraFields = computed(() => filterServerList.value?.fields || {});
|
|
||||||
|
|
||||||
const {
|
|
||||||
billAndPlan,
|
|
||||||
} = handleServerBillAndPlan({
|
|
||||||
props,
|
|
||||||
});
|
|
||||||
|
|
||||||
const buyBtnText = computed(() => config.nazhua.buyBtnText || '购买');
|
|
||||||
const showBuyBtn = computed(() => !!props.info?.PublicNote?.customData?.orderLink);
|
|
||||||
|
|
||||||
function toBuy() {
|
|
||||||
const decodeUrl = decodeURIComponent(props.info?.PublicNote?.customData?.orderLink);
|
|
||||||
window.open(decodeUrl, '_blank');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.order-link {
|
|
||||||
color: var(--list-item-buy-link-color);
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: var(--list-item-buy-link-color-hover);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,45 +0,0 @@
|
|||||||
<template>
|
|
||||||
<server-list-column
|
|
||||||
v-for="item in serverRealTimeList"
|
|
||||||
:key="item.key"
|
|
||||||
:prop="item.key"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.show ? item?.value : '-'"
|
|
||||||
:unit="item.show ? item?.unit : ''"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 服务器数据统计
|
|
||||||
*/
|
|
||||||
import {
|
|
||||||
inject,
|
|
||||||
} from 'vue';
|
|
||||||
import handleServerRealTime from '@/views/composable/server-real-time';
|
|
||||||
|
|
||||||
import ServerListColumn from './server-list-column.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
serverRealTimeListTpls: {
|
|
||||||
type: String,
|
|
||||||
default: undefined,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const currentTime = inject('currentTime', {
|
|
||||||
value: Date.now(),
|
|
||||||
});
|
|
||||||
|
|
||||||
const {
|
|
||||||
serverRealTimeList,
|
|
||||||
} = handleServerRealTime({
|
|
||||||
props,
|
|
||||||
currentTime,
|
|
||||||
serverRealTimeListTpls: props.serverRealTimeListTpls,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
@ -1,143 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
class="server-list-item-status-progress"
|
|
||||||
:class="'server-status--' + type"
|
|
||||||
:title="valPercent"
|
|
||||||
>
|
|
||||||
<span class="progress-label">
|
|
||||||
{{ label }}
|
|
||||||
</span>
|
|
||||||
<div class="progress-bar">
|
|
||||||
<div class="progress-bar-box">
|
|
||||||
<div
|
|
||||||
class="progress-bar-inner"
|
|
||||||
:style="progressStyle"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="progress-bar-used"
|
|
||||||
>
|
|
||||||
{{ valText }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 服务器状态进度调单项
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
computed,
|
|
||||||
} from 'vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
type: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
size: {
|
|
||||||
type: Number,
|
|
||||||
default: 100,
|
|
||||||
},
|
|
||||||
used: {
|
|
||||||
type: [Number, String],
|
|
||||||
default: 1,
|
|
||||||
},
|
|
||||||
colors: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
valText: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
valPercent: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
content: {
|
|
||||||
type: [String, Object],
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const progressStyle = computed(() => {
|
|
||||||
const style = {};
|
|
||||||
style.width = `${Math.min(props.used, 100)}%`;
|
|
||||||
const color = typeof props.colors === 'string' ? props.colors : props.colors?.used;
|
|
||||||
if (color) {
|
|
||||||
if (Array.isArray(color)) {
|
|
||||||
style.background = `linear-gradient(-35deg, ${color.join(',')})`;
|
|
||||||
} else {
|
|
||||||
style.backgroundColor = color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return style;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.server-list-item-status-progress {
|
|
||||||
--progress-label-height: 16px;
|
|
||||||
--progress-bar-height: 24px;
|
|
||||||
--progress-bar-box-height: 14px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: var(--list-item-height);
|
|
||||||
|
|
||||||
.progress-label {
|
|
||||||
padding-top: 6px; // 视觉修正
|
|
||||||
line-height: var(--progress-label-height);
|
|
||||||
font-size: 12px;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
height: var(--progress-bar-height);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-box {
|
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
height: var(--progress-bar-box-height);
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
border-radius: calc(var(--progress-bar-box-height) / 2);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-inner {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: #08f;
|
|
||||||
border-radius: calc(var(--progress-bar-box-height) / 2);
|
|
||||||
box-shadow: 2px 0 2px rgba(#000, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress-bar-used {
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
line-height: var(--progress-bar-box-height);
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: center;
|
|
||||||
text-shadow: 1px 1px 2px rgba(#000, 0.8), 0 0 1px rgba(#fff, 0.5);
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div
|
|
||||||
v-for="item in serverStatusList"
|
|
||||||
:key="item.type"
|
|
||||||
class="list-column-item list-column-item--status"
|
|
||||||
:class="`list-column-item--status-${componentName} list-column-item--status-type-${item.type}`"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="componentMaps[componentName]"
|
|
||||||
:type="item.type"
|
|
||||||
:used="item.used"
|
|
||||||
:colors="item.colors"
|
|
||||||
:val-text="item.valPercent"
|
|
||||||
:val-percent="`${item.label}使用${item.valText}`"
|
|
||||||
:label="item.label"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 服务器状态盒子
|
|
||||||
*/
|
|
||||||
|
|
||||||
import config from '@/config';
|
|
||||||
|
|
||||||
import handleServerStatus from '@/views/composable/server-status';
|
|
||||||
import ServerStatusDonut from '@/views/components/server/server-status-donut.vue';
|
|
||||||
import ServerStatusProgress from './server-list-item-status-progress.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const componentMaps = {
|
|
||||||
donut: ServerStatusDonut,
|
|
||||||
progress: ServerStatusProgress,
|
|
||||||
};
|
|
||||||
|
|
||||||
const componentName = [
|
|
||||||
'donut',
|
|
||||||
'progress',
|
|
||||||
].includes(config.nazhua.listServerStatusType) ? config.nazhua.listServerStatusType : 'donut';
|
|
||||||
|
|
||||||
const {
|
|
||||||
serverStatusList,
|
|
||||||
} = handleServerStatus({
|
|
||||||
props,
|
|
||||||
statusListTpl: 'cpu,mem,disk',
|
|
||||||
statusListItemContent: false,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.list-column-item {
|
|
||||||
&--status-progress {
|
|
||||||
width: 72px;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--status-donut {
|
|
||||||
--server-status-size: 66px;
|
|
||||||
--server-status-label-scale: 0.8;
|
|
||||||
--server-status-val-text-font-size: 16px;
|
|
||||||
--server-status-label-font-size: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,174 +0,0 @@
|
|||||||
<template>
|
|
||||||
<dot-dot-box
|
|
||||||
border-radius="var(--list-item-border-radius)"
|
|
||||||
padding="var(--list-item-padding)"
|
|
||||||
class="server-list-row-item"
|
|
||||||
:class="{
|
|
||||||
'server-list-row-item--offline': info.online === -1,
|
|
||||||
}"
|
|
||||||
@click="openDetail"
|
|
||||||
>
|
|
||||||
<div class="list-column-item list-column-item--server-flag">
|
|
||||||
<span
|
|
||||||
class="server-flag"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
class="fi"
|
|
||||||
:class="'fi-' + (info?.Host?.CountryCode || 'un')"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="list-column-item list-column-item--server-name">
|
|
||||||
<span
|
|
||||||
class="server-name"
|
|
||||||
:title="info.Name"
|
|
||||||
>
|
|
||||||
{{ info.Name }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<server-list-column
|
|
||||||
prop="server-flag"
|
|
||||||
label="地区"
|
|
||||||
:value="info?.Host?.CountryCode?.toUpperCase() || 'UN'"
|
|
||||||
/>
|
|
||||||
<server-list-column
|
|
||||||
prop="server-system"
|
|
||||||
label="系统"
|
|
||||||
:value="platformSystemLabel || '-'"
|
|
||||||
/>
|
|
||||||
<server-list-column
|
|
||||||
prop="cpu-mem"
|
|
||||||
label="配置"
|
|
||||||
:value="cpuAndMemAndDisk || '-'"
|
|
||||||
/>
|
|
||||||
<server-list-item-status
|
|
||||||
v-if="$config.nazhua.hideListItemStatusDonut !== true"
|
|
||||||
:info="info"
|
|
||||||
/>
|
|
||||||
<server-list-item-real-time
|
|
||||||
v-if="$config.nazhua.hideListItemStat !== true"
|
|
||||||
:info="info"
|
|
||||||
server-real-time-list-tpls="load,inSpeed,outSpeed,transfer,duration"
|
|
||||||
/>
|
|
||||||
<server-list-item-bill
|
|
||||||
v-if="$config.nazhua.hideListItemBill !== true"
|
|
||||||
:info="info"
|
|
||||||
/>
|
|
||||||
</dot-dot-box>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
/**
|
|
||||||
* 单节点
|
|
||||||
*/
|
|
||||||
|
|
||||||
import {
|
|
||||||
computed,
|
|
||||||
} from 'vue';
|
|
||||||
import {
|
|
||||||
useRouter,
|
|
||||||
} from 'vue-router';
|
|
||||||
import * as hostUtils from '@/utils/host';
|
|
||||||
|
|
||||||
import handleServerInfo from '@/views/composable/server-info';
|
|
||||||
import ServerListColumn from './server-list-column.vue';
|
|
||||||
import ServerListItemStatus from './server-list-item-status.vue';
|
|
||||||
import ServerListItemRealTime from './server-list-item-real-time.vue';
|
|
||||||
import ServerListItemBill from './server-list-item-bill.vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
info: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XCore XGB
|
|
||||||
*/
|
|
||||||
const { cpuAndMemAndDisk } = handleServerInfo({
|
|
||||||
props,
|
|
||||||
});
|
|
||||||
|
|
||||||
const platformSystemLabel = computed(() => hostUtils.getSystemOSLabel(props.info?.Host?.Platform));
|
|
||||||
|
|
||||||
function openDetail() {
|
|
||||||
router.push({
|
|
||||||
name: 'ServerDetail',
|
|
||||||
params: {
|
|
||||||
serverId: props.info.ID,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.server-list-row-item {
|
|
||||||
--list-item-height: 64px;
|
|
||||||
--list-item-border-radius: 8px;
|
|
||||||
--list-item-gap: 0;
|
|
||||||
--list-item-padding: 0 20px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
height: var(--list-item-height);
|
|
||||||
gap: var(--list-item-gap);
|
|
||||||
transition: 0.3s;
|
|
||||||
|
|
||||||
&--offline {
|
|
||||||
filter: grayscale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1280px) {
|
|
||||||
--list-item-padding: 0 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-column-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
&--server-flag {
|
|
||||||
--server-flag-size: 24px;
|
|
||||||
width: calc(var(--server-flag-size) * 1.5);
|
|
||||||
.server-flag {
|
|
||||||
width: calc(var(--server-flag-size) * 1.5);
|
|
||||||
height: var(--server-flag-size);
|
|
||||||
line-height: var(--server-flag-size);
|
|
||||||
font-size: var(--server-flag-size);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1280px) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&--server-name {
|
|
||||||
width: 220px;
|
|
||||||
|
|
||||||
.server-name {
|
|
||||||
height: 32px;
|
|
||||||
line-height: 34px;
|
|
||||||
font-size: 16px;
|
|
||||||
width: 100%;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1280px) {
|
|
||||||
width: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
|
||||||
width: 300px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -12,7 +12,7 @@
|
|||||||
<template #default>
|
<template #default>
|
||||||
<div
|
<div
|
||||||
class="chart-donut-label"
|
class="chart-donut-label"
|
||||||
:title="valPercent ? valPercent : `${(used).toFixed(1) * 1}%`"
|
:title="`${(used).toFixed(1) * 1}%`"
|
||||||
>
|
>
|
||||||
<div class="server-status-val-text">
|
<div class="server-status-val-text">
|
||||||
<span>{{ valText }}</span>
|
<span>{{ valText }}</span>
|
||||||
@ -73,10 +73,6 @@ defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
valPercent: {
|
|
||||||
type: String,
|
|
||||||
default: '',
|
|
||||||
},
|
|
||||||
label: {
|
label: {
|
||||||
type: String,
|
type: String,
|
||||||
default: '',
|
default: '',
|
||||||
@ -107,7 +103,6 @@ defineProps({
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
transform: scale(var(--server-status-label-scale, 1));
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -25,8 +25,7 @@ export default (params) => {
|
|||||||
billingDataMod,
|
billingDataMod,
|
||||||
planDataMod,
|
planDataMod,
|
||||||
} = props.info.PublicNote;
|
} = props.info.PublicNote;
|
||||||
// 默认1个月
|
let months;
|
||||||
let months = 1;
|
|
||||||
// 套餐资费
|
// 套餐资费
|
||||||
let cycleLabel;
|
let cycleLabel;
|
||||||
if (validate.isSet(billingDataMod?.cycle)) {
|
if (validate.isSet(billingDataMod?.cycle)) {
|
||||||
|
|||||||
@ -122,44 +122,6 @@ export default (params) => {
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
const inTransfer = computed(() => {
|
|
||||||
const inStats = hostUtils.calcBinary(props.info?.State?.NetInTransfer || 0);
|
|
||||||
const result = {
|
|
||||||
value: 0,
|
|
||||||
unit: '',
|
|
||||||
};
|
|
||||||
if (inStats.g > 1) {
|
|
||||||
result.value = (inStats.g).toFixed(1) * 1;
|
|
||||||
result.unit = 'G';
|
|
||||||
} else if (inStats.m > 1) {
|
|
||||||
result.value = (inStats.m).toFixed(1) * 1;
|
|
||||||
result.unit = 'M';
|
|
||||||
} else {
|
|
||||||
result.value = (inStats.k).toFixed(1) * 1;
|
|
||||||
result.unit = 'K';
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
|
|
||||||
const outTransfer = computed(() => {
|
|
||||||
const outStats = hostUtils.calcBinary(props.info?.State?.NetOutTransfer || 0);
|
|
||||||
const result = {
|
|
||||||
value: 0,
|
|
||||||
unit: '',
|
|
||||||
};
|
|
||||||
if (outStats.g > 1) {
|
|
||||||
result.value = (outStats.g).toFixed(1) * 1;
|
|
||||||
result.unit = 'G';
|
|
||||||
} else if (outStats.m > 1) {
|
|
||||||
result.value = (outStats.m).toFixed(1) * 1;
|
|
||||||
result.unit = 'M';
|
|
||||||
} else {
|
|
||||||
result.value = (outStats.k).toFixed(1) * 1;
|
|
||||||
result.unit = 'K';
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算入向网速
|
* 计算入向网速
|
||||||
*/
|
*/
|
||||||
@ -222,22 +184,6 @@ export default (params) => {
|
|||||||
unit: transfer.value?.unit,
|
unit: transfer.value?.unit,
|
||||||
show: validate.isSet(transfer.value?.value),
|
show: validate.isSet(transfer.value?.value),
|
||||||
};
|
};
|
||||||
case 'inTransfer':
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
label: '入网流量',
|
|
||||||
value: inTransfer.value?.value,
|
|
||||||
unit: inTransfer.value?.unit,
|
|
||||||
show: validate.isSet(inTransfer.value?.value),
|
|
||||||
};
|
|
||||||
case 'outTransfer':
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
label: '出网流量',
|
|
||||||
value: outTransfer.value?.value,
|
|
||||||
unit: outTransfer.value?.unit,
|
|
||||||
show: validate.isSet(outTransfer.value?.value),
|
|
||||||
};
|
|
||||||
case 'inSpeed':
|
case 'inSpeed':
|
||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
@ -280,7 +226,7 @@ export default (params) => {
|
|||||||
return {
|
return {
|
||||||
key,
|
key,
|
||||||
label: '负载',
|
label: '负载',
|
||||||
value: (props.info.State?.Load1 || 0).toFixed(2),
|
value: (props.info.State?.Load1 || 0).toFixed(2) * 1,
|
||||||
unit: '',
|
unit: '',
|
||||||
show: validate.isSet(props.info.State?.Load1),
|
show: validate.isSet(props.info.State?.Load1),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -65,8 +65,6 @@ export default (params) => {
|
|||||||
{
|
{
|
||||||
const CoresVal = cpuInfo.value?.cores ? `${cpuInfo.value?.cores}C` : '-';
|
const CoresVal = cpuInfo.value?.cores ? `${cpuInfo.value?.cores}C` : '-';
|
||||||
const usedColor = config.nazhua.serverStatusLinear ? ['#0088FF', '#72B7FF'] : '#0088FF';
|
const usedColor = config.nazhua.serverStatusLinear ? ['#0088FF', '#72B7FF'] : '#0088FF';
|
||||||
const valPercent = `${(props.info.State?.CPU || 0).toFixed(1) * 1}%`;
|
|
||||||
const valText = valPercent;
|
|
||||||
return {
|
return {
|
||||||
type: 'cpu',
|
type: 'cpu',
|
||||||
used: (props.info.State?.CPU || 0).toFixed(1) * 1,
|
used: (props.info.State?.CPU || 0).toFixed(1) * 1,
|
||||||
@ -74,8 +72,7 @@ export default (params) => {
|
|||||||
used: usedColor,
|
used: usedColor,
|
||||||
total: 'rgba(255, 255, 255, 0.25)',
|
total: 'rgba(255, 255, 255, 0.25)',
|
||||||
},
|
},
|
||||||
valText,
|
valText: `${(props.info.State?.CPU || 0).toFixed(1) * 1}%`,
|
||||||
valPercent,
|
|
||||||
label: 'CPU',
|
label: 'CPU',
|
||||||
content: {
|
content: {
|
||||||
default: cpuInfo.value?.core || CoresVal,
|
default: cpuInfo.value?.core || CoresVal,
|
||||||
@ -85,11 +82,11 @@ export default (params) => {
|
|||||||
}
|
}
|
||||||
case 'mem':
|
case 'mem':
|
||||||
{
|
{
|
||||||
let valText;
|
let usedVal;
|
||||||
if (useMemAndTotalMem.value.used.g >= 10 && useMemAndTotalMem.value.total.g >= 10) {
|
if (useMemAndTotalMem.value.used.g >= 10 && useMemAndTotalMem.value.total.g >= 10) {
|
||||||
valText = `${(useMemAndTotalMem.value.used.g).toFixed(1) * 1}G`;
|
usedVal = `${(useMemAndTotalMem.value.used.g).toFixed(1) * 1}G`;
|
||||||
} else {
|
} else {
|
||||||
valText = `${Math.ceil(useMemAndTotalMem.value.used.m)}M`;
|
usedVal = `${Math.ceil(useMemAndTotalMem.value.used.m)}M`;
|
||||||
}
|
}
|
||||||
let contentVal;
|
let contentVal;
|
||||||
if (useMemAndTotalMem.value.total.g > 4) {
|
if (useMemAndTotalMem.value.total.g > 4) {
|
||||||
@ -105,8 +102,7 @@ export default (params) => {
|
|||||||
used: usedColor,
|
used: usedColor,
|
||||||
total: 'rgba(255, 255, 255, 0.25)',
|
total: 'rgba(255, 255, 255, 0.25)',
|
||||||
},
|
},
|
||||||
valText,
|
valText: usedVal,
|
||||||
valPercent: `${useMemAndTotalMem.value.usePercent.toFixed(1) * 1}%`,
|
|
||||||
label: '内存',
|
label: '内存',
|
||||||
content: {
|
content: {
|
||||||
default: `运行内存${contentVal}`,
|
default: `运行内存${contentVal}`,
|
||||||
@ -119,11 +115,11 @@ export default (params) => {
|
|||||||
if (!useSwapAndTotalSwap.value) {
|
if (!useSwapAndTotalSwap.value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
let valText;
|
let usedVal;
|
||||||
if (useSwapAndTotalSwap.value.used.g >= 10 && useSwapAndTotalSwap.value.total.g >= 10) {
|
if (useSwapAndTotalSwap.value.used.g >= 10 && useSwapAndTotalSwap.value.total.g >= 10) {
|
||||||
valText = `${(useSwapAndTotalSwap.value.used.g).toFixed(1) * 1}G`;
|
usedVal = `${(useSwapAndTotalSwap.value.used.g).toFixed(1) * 1}G`;
|
||||||
} else {
|
} else {
|
||||||
valText = `${Math.ceil(useSwapAndTotalSwap.value.used.m)}M`;
|
usedVal = `${Math.ceil(useSwapAndTotalSwap.value.used.m)}M`;
|
||||||
}
|
}
|
||||||
let contentVal;
|
let contentVal;
|
||||||
if (useSwapAndTotalSwap.value.total.g > 4) {
|
if (useSwapAndTotalSwap.value.total.g > 4) {
|
||||||
@ -139,8 +135,7 @@ export default (params) => {
|
|||||||
used: usedColor,
|
used: usedColor,
|
||||||
total: 'rgba(255, 255, 255, 0.25)',
|
total: 'rgba(255, 255, 255, 0.25)',
|
||||||
},
|
},
|
||||||
valText,
|
valText: usedVal,
|
||||||
valPercent: `${useSwapAndTotalSwap.value.usePercent.toFixed(1) * 1}%`,
|
|
||||||
label: '交换',
|
label: '交换',
|
||||||
content: {
|
content: {
|
||||||
default: `交换内存${contentVal}`,
|
default: `交换内存${contentVal}`,
|
||||||
@ -165,7 +160,6 @@ export default (params) => {
|
|||||||
total: 'rgba(255, 255, 255, 0.25)',
|
total: 'rgba(255, 255, 255, 0.25)',
|
||||||
},
|
},
|
||||||
valText: `${(useDiskAndTotalDisk.value.used.g).toFixed(1) * 1}G`,
|
valText: `${(useDiskAndTotalDisk.value.used.g).toFixed(1) * 1}G`,
|
||||||
valPercent: `${useDiskAndTotalDisk.value.usePercent.toFixed(1) * 1}%`,
|
|
||||||
label: '磁盘',
|
label: '磁盘',
|
||||||
content: {
|
content: {
|
||||||
default: `磁盘容量${contentValue}`,
|
default: `磁盘容量${contentValue}`,
|
||||||
|
|||||||
@ -13,10 +13,6 @@
|
|||||||
<div
|
<div
|
||||||
v-if="showFilter"
|
v-if="showFilter"
|
||||||
class="fitler-group"
|
class="fitler-group"
|
||||||
:class="{
|
|
||||||
'list-is-row': showListRow,
|
|
||||||
'list-is-card': showListCard,
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<server-option-box
|
<server-option-box
|
||||||
@ -34,27 +30,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition-group
|
<transition-group
|
||||||
v-if="showListRow"
|
|
||||||
name="list"
|
name="list"
|
||||||
tag="div"
|
tag="div"
|
||||||
class="server-list-container"
|
class="server-list-container"
|
||||||
:class="`server-list--row`"
|
|
||||||
>
|
>
|
||||||
<server-row-item
|
<server-item
|
||||||
v-for="item in filterServerList.list"
|
v-for="item in filterServerList"
|
||||||
:key="item.ID"
|
|
||||||
:info="item"
|
|
||||||
/>
|
|
||||||
</transition-group>
|
|
||||||
<transition-group
|
|
||||||
v-if="showListCard"
|
|
||||||
name="list"
|
|
||||||
tag="div"
|
|
||||||
class="server-list-container"
|
|
||||||
:class="`server-list--card`"
|
|
||||||
>
|
|
||||||
<server-card-item
|
|
||||||
v-for="item in filterServerList.list"
|
|
||||||
:key="item.ID"
|
:key="item.ID"
|
||||||
:info="item"
|
:info="item"
|
||||||
/>
|
/>
|
||||||
@ -70,7 +51,6 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
ref,
|
ref,
|
||||||
provide,
|
|
||||||
computed,
|
computed,
|
||||||
onMounted,
|
onMounted,
|
||||||
onUnmounted,
|
onUnmounted,
|
||||||
@ -86,29 +66,13 @@ import {
|
|||||||
count2size,
|
count2size,
|
||||||
} from '@/utils/world-map';
|
} from '@/utils/world-map';
|
||||||
import uuid from '@/utils/uuid';
|
import uuid from '@/utils/uuid';
|
||||||
import validate from '@/utils/validate';
|
|
||||||
|
|
||||||
import WorldMap from '@/components/world-map/world-map.vue';
|
import WorldMap from '@/components/world-map/world-map.vue';
|
||||||
import ServerOptionBox from './components/server-list/server-option-box.vue';
|
import ServerOptionBox from './components/server-list/server-option-box.vue';
|
||||||
import ServerCardItem from './components/server-list/card/server-list-item.vue';
|
import ServerItem from './components/server-list/server-list-item.vue';
|
||||||
import ServerRowItem from './components/server-list/row/server-list-item.vue';
|
|
||||||
|
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const worldMapWidth = ref();
|
const worldMapWidth = ref();
|
||||||
const windowWidth = ref(window.innerWidth);
|
|
||||||
|
|
||||||
const showListRow = computed(() => {
|
|
||||||
if (windowWidth.value > 1024) {
|
|
||||||
return config.nazhua.listServerItemType === 'row';
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
const showListCard = computed(() => {
|
|
||||||
if (windowWidth.value > 1024) {
|
|
||||||
return config.nazhua.listServerItemType !== 'row';
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
const showFilter = computed(() => config.nazhua.hideFilter !== true);
|
const showFilter = computed(() => config.nazhua.hideFilter !== true);
|
||||||
const filterFormData = ref({
|
const filterFormData = ref({
|
||||||
@ -156,11 +120,7 @@ const onlineOptions = computed(() => {
|
|||||||
return [];
|
return [];
|
||||||
});
|
});
|
||||||
|
|
||||||
const filterServerList = computed(() => {
|
const filterServerList = computed(() => serverList.value.filter((i) => {
|
||||||
const fields = {};
|
|
||||||
const locationMap = {};
|
|
||||||
|
|
||||||
const list = serverList.value.filter((i) => {
|
|
||||||
const isFilterArr = [];
|
const isFilterArr = [];
|
||||||
if (filterFormData.value.tag) {
|
if (filterFormData.value.tag) {
|
||||||
const group = store.state.serverGroup.find((o) => o.name === filterFormData.value.tag);
|
const group = store.state.serverGroup.find((o) => o.name === filterFormData.value.tag);
|
||||||
@ -169,34 +129,18 @@ const filterServerList = computed(() => {
|
|||||||
if (filterFormData.value.online) {
|
if (filterFormData.value.online) {
|
||||||
isFilterArr.push(i.online === (filterFormData.value.online * 1));
|
isFilterArr.push(i.online === (filterFormData.value.online * 1));
|
||||||
}
|
}
|
||||||
const status = isFilterArr.length ? isFilterArr.every((o) => o) : true;
|
return isFilterArr.length ? isFilterArr.every((o) => o) : true;
|
||||||
if (!status) {
|
}));
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断是否有字段
|
/**
|
||||||
if (i.PublicNote) {
|
* 解构服务器列表的位置数据
|
||||||
const {
|
*/
|
||||||
billingDataMod,
|
const serverLocations = computed(() => {
|
||||||
planDataMod,
|
const locationMap = {};
|
||||||
customData,
|
filterServerList.value.forEach((i) => {
|
||||||
} = i.PublicNote;
|
if (i.online === -1) {
|
||||||
if (validate.isSet(billingDataMod?.amount)) {
|
return;
|
||||||
fields.billing = true;
|
|
||||||
}
|
}
|
||||||
if (validate.isSet(billingDataMod?.endDate)) {
|
|
||||||
fields.remainingTime = true;
|
|
||||||
}
|
|
||||||
if (validate.isSet(planDataMod?.bandwidth)) {
|
|
||||||
fields.bandwidth = true;
|
|
||||||
}
|
|
||||||
if (validate.isSet(customData?.orderLink)) {
|
|
||||||
fields.orderLink = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 位置
|
|
||||||
if (i.online === 1) {
|
|
||||||
let aliasCode;
|
let aliasCode;
|
||||||
let locationCode;
|
let locationCode;
|
||||||
if (i?.PublicNote?.customData?.location) {
|
if (i?.PublicNote?.customData?.location) {
|
||||||
@ -212,24 +156,9 @@ const filterServerList = computed(() => {
|
|||||||
}
|
}
|
||||||
locationMap[code].push(i);
|
locationMap[code].push(i);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
});
|
||||||
return {
|
|
||||||
fields,
|
|
||||||
list,
|
|
||||||
locationMap,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
provide('filterServerList', filterServerList);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 解构服务器列表的位置数据
|
|
||||||
*/
|
|
||||||
const serverLocations = computed(() => {
|
|
||||||
const locations = [];
|
const locations = [];
|
||||||
Object.entries(filterServerList.value.locationMap).forEach(([code, servers]) => {
|
Object.entries(locationMap).forEach(([code, servers]) => {
|
||||||
const {
|
const {
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
@ -268,7 +197,6 @@ const showWorldMap = computed(() => {
|
|||||||
*/
|
*/
|
||||||
function handleResize() {
|
function handleResize() {
|
||||||
worldMapWidth.value = document.querySelector('.server-list-container').clientWidth - 40;
|
worldMapWidth.value = document.querySelector('.server-list-container').clientWidth - 40;
|
||||||
windowWidth.value = window.innerWidth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -286,35 +214,6 @@ onUnmounted(() => {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.scroll-container {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
padding: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.world-map-box {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fitler-group {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: space-between;
|
|
||||||
gap: 10px 20px;
|
|
||||||
width: var(--list-container-width);
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
&.list-is-card {
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.server-list-container.server-list--card {
|
|
||||||
--list-padding: 20px;
|
--list-padding: 20px;
|
||||||
--list-gap-size: 20px;
|
--list-gap-size: 20px;
|
||||||
--list-item-num: 3;
|
--list-item-num: 3;
|
||||||
@ -329,6 +228,21 @@ onUnmounted(() => {
|
|||||||
)
|
)
|
||||||
/ var(--list-item-num)
|
/ var(--list-item-num)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
padding: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.world-map-box {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.server-list-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@ -336,6 +250,7 @@ onUnmounted(() => {
|
|||||||
padding: 0 var(--list-padding);
|
padding: 0 var(--list-padding);
|
||||||
width: var(--list-container-width);
|
width: var(--list-container-width);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
// 针对1440px以下的屏幕
|
// 针对1440px以下的屏幕
|
||||||
@media screen and (max-width: 1440px) {
|
@media screen and (max-width: 1440px) {
|
||||||
@ -351,13 +266,11 @@ onUnmounted(() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.server-list-container.server-list--row {
|
.fitler-group {
|
||||||
--list-padding: 20px;
|
|
||||||
--list-gap-size: 12px;
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-wrap: wrap;
|
||||||
gap: var(--list-gap-size);
|
justify-content: space-between;
|
||||||
|
gap: 10px 20px;
|
||||||
width: var(--list-container-width);
|
width: var(--list-container-width);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user