mirror of
https://github.com/hi2shark/nazhua.git
synced 2026-01-12 15:20:43 +08:00
✨ 新增行列的单独组件
This commit is contained in:
parent
5ec81d7616
commit
3501483af0
162
src/views/components/server-list/row/server-list-column.vue
Normal file
162
src/views/components/server-list/row/server-list-column.vue
Normal file
@ -0,0 +1,162 @@
|
||||
<template>
|
||||
<div
|
||||
class="list-column"
|
||||
:class="`list-column--${prop}`"
|
||||
:style="columnStyle"
|
||||
>
|
||||
<div 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,
|
||||
} from 'vue';
|
||||
|
||||
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 columnStyle = computed(() => {
|
||||
const style = {};
|
||||
const width = parseInt(props.width, 10);
|
||||
if (Number.isNaN(width) === false) {
|
||||
style.width = `${width}px`;
|
||||
}
|
||||
return style;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-column {
|
||||
width: 50px;
|
||||
|
||||
.list-column-content {
|
||||
--list-column-label-height: 16px;
|
||||
--list-column-value-height: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
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 {
|
||||
width: 80px;
|
||||
.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 {
|
||||
width: 60px;
|
||||
.value-text {
|
||||
color: #74dbef;
|
||||
}
|
||||
}
|
||||
|
||||
&--billing {
|
||||
width: 60px;
|
||||
.value-text {
|
||||
color: var(--list-item-price-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,49 +1,32 @@
|
||||
<template>
|
||||
<div
|
||||
<server-list-column
|
||||
v-if="extraFields?.remainingTime"
|
||||
class="list-column-item list-column-item--remaining-time"
|
||||
>
|
||||
<div class="list-column-item-content">
|
||||
<span class="item-label">剩余</span>
|
||||
<div class="item-content">
|
||||
<span class="text-item value-text">{{ billAndPlan?.remainingTime?.value || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
prop="remaining-time"
|
||||
label="剩余"
|
||||
:value="billAndPlan?.remainingTime?.value || '-'"
|
||||
/>
|
||||
<server-list-column
|
||||
v-if="extraFields?.billing"
|
||||
class="list-column-item list-column-item--billing"
|
||||
>
|
||||
<div class="list-column-item-content">
|
||||
<span
|
||||
v-if="!billAndPlan?.billing?.isFree && billAndPlan?.billing?.label"
|
||||
class="item-label"
|
||||
>
|
||||
{{ billAndPlan.billing.label }}
|
||||
</span>
|
||||
<div class="item-content">
|
||||
<span class="text-item value-text">{{ billAndPlan?.billing?.value || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
prop="billing"
|
||||
label="费用"
|
||||
:value="billAndPlan?.billing?.value || '-'"
|
||||
/>
|
||||
<server-list-column
|
||||
v-if="extraFields?.orderLink"
|
||||
class="list-column-item list-column-item--order-link"
|
||||
prop="order-link"
|
||||
label="链接"
|
||||
wdith="80"
|
||||
:slot-content="true"
|
||||
>
|
||||
<div class="list-column-item-content">
|
||||
<span class="item-label">链接</span>
|
||||
<div class="item-content">
|
||||
<span
|
||||
v-if="showBuyBtn"
|
||||
class="text-item value-text"
|
||||
@click="toBuy"
|
||||
>
|
||||
{{ buyBtnText }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
v-if="showBuyBtn"
|
||||
class="order-link"
|
||||
@click="toBuy"
|
||||
>
|
||||
{{ buyBtnText }}
|
||||
</span>
|
||||
<span v-else>-</span>
|
||||
</server-list-column>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -59,6 +42,8 @@ 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,
|
||||
@ -81,60 +66,15 @@ const {
|
||||
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');
|
||||
// }
|
||||
function toBuy() {
|
||||
const decodeUrl = decodeURIComponent(props.info?.PublicNote?.customData?.orderLink);
|
||||
window.open(decodeUrl, '_blank');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-column-item {
|
||||
|
||||
.list-column-item-content {
|
||||
--item-content-label-height: 16px;
|
||||
--item-content-value-height: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: var(--list-item-height);
|
||||
|
||||
.item-label {
|
||||
padding-top: 6px; // 视觉修正
|
||||
line-height: var(--item-content-label-height);
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
line-height: var(--item-content-value-height);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
&--remaining-time {
|
||||
width: 60px;
|
||||
|
||||
.value-text {
|
||||
color: #74dbef;
|
||||
}
|
||||
}
|
||||
|
||||
&--billing {
|
||||
width: 60px;
|
||||
|
||||
.value-text {
|
||||
color: var(--list-item-price-color);
|
||||
}
|
||||
}
|
||||
|
||||
&--order-link {
|
||||
width: 60px;
|
||||
|
||||
.value-text {
|
||||
color: var(--list-item-buy-link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.order-link {
|
||||
color: var(--list-item-buy-link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -1,18 +1,12 @@
|
||||
<template>
|
||||
<div
|
||||
<server-list-column
|
||||
v-for="item in serverRealTimeList"
|
||||
:key="item.key"
|
||||
class="list-column-item list-column-item--real-time"
|
||||
:class="`list-column-item--real-time-${item.key}`"
|
||||
>
|
||||
<div class="real-time-content">
|
||||
<span class="item-label">{{ item.label }}</span>
|
||||
<div class="item-content">
|
||||
<span class="item-value">{{ item.show ? item?.value : '-' }}</span>
|
||||
<span class="item-unit item-text">{{ item.show ? item?.unit : '' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
:prop="item.key"
|
||||
:label="item.label"
|
||||
:value="item.show ? item?.value : '-'"
|
||||
:unit="item.show ? item?.unit : ''"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
@ -24,6 +18,8 @@ import {
|
||||
} from 'vue';
|
||||
import handleServerRealTime from '@/views/composable/server-real-time';
|
||||
|
||||
import ServerListColumn from './server-list-column.vue';
|
||||
|
||||
const props = defineProps({
|
||||
info: {
|
||||
type: Object,
|
||||
@ -47,59 +43,3 @@ const {
|
||||
serverRealTimeListTpls: props.serverRealTimeListTpls,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.list-column-item {
|
||||
.real-time-content {
|
||||
--real-time-label-height: 16px;
|
||||
--real-time-value-height: 24px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: var(--list-item-height);
|
||||
|
||||
.item-label {
|
||||
padding-top: 6px; // 视觉修正
|
||||
line-height: var(--real-time-label-height);
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
.item-content {
|
||||
line-height: var(--real-time-value-height);
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
&--real-time-duration {
|
||||
width: 50px;
|
||||
.item-value {
|
||||
color: var(--duration-color);
|
||||
}
|
||||
}
|
||||
&--real-time-load {
|
||||
width: 50px;
|
||||
.item-value {
|
||||
color: var(--load-color);
|
||||
}
|
||||
}
|
||||
&--real-time-transfer {
|
||||
width: 80px;
|
||||
.item-value {
|
||||
color: var(--transfer-color);
|
||||
}
|
||||
}
|
||||
&--real-time-inSpeed {
|
||||
width: 50px;
|
||||
.item-value {
|
||||
color: var(--net-speed-in-color);
|
||||
}
|
||||
}
|
||||
&--real-time-outSpeed {
|
||||
width: 50px;
|
||||
.item-value {
|
||||
color: var(--net-speed-out-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -8,43 +8,59 @@
|
||||
}"
|
||||
@click="openDetail"
|
||||
>
|
||||
<div class="list-column-item list-column-item--server-flag">
|
||||
<span
|
||||
class="server-flag"
|
||||
>
|
||||
<div class="row-left-box">
|
||||
<div class="list-column-item list-column-item--server-flag">
|
||||
<span
|
||||
class="fi"
|
||||
:class="'fi-' + (info?.Host?.CountryCode || 'un')"
|
||||
/>
|
||||
</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="配置"
|
||||
width="80"
|
||||
:value="cpuAndMemAndDisk || '-'"
|
||||
/>
|
||||
</div>
|
||||
<div class="list-column-item list-column-item--server-name">
|
||||
<span
|
||||
class="server-name"
|
||||
:title="info.Name"
|
||||
>
|
||||
{{ info.Name }}
|
||||
</span>
|
||||
<div class="row-center-box">
|
||||
<server-list-item-status
|
||||
v-if="$config.nazhua.hideListItemStatusDonut !== true"
|
||||
:info="info"
|
||||
/>
|
||||
</div>
|
||||
<div class="list-column-item list-column-item--server-system">
|
||||
<span :class="platformLogoIconClassName" />
|
||||
<div class="row-right-box">
|
||||
<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"
|
||||
/>
|
||||
</div>
|
||||
<div class="list-column-item list-column-item--cpu-mem">
|
||||
<span class="core-mem">{{ cpuAndMemAndDisk || '-' }}</span>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
@ -62,6 +78,7 @@ import {
|
||||
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';
|
||||
@ -82,7 +99,7 @@ const { cpuAndMemAndDisk } = handleServerInfo({
|
||||
props,
|
||||
});
|
||||
|
||||
const platformLogoIconClassName = computed(() => hostUtils.getPlatformLogoIconClassName(props.info?.Host?.Platform));
|
||||
const platformSystemLabel = computed(() => hostUtils.getSystemOSLabel(props.info?.Host?.Platform));
|
||||
|
||||
function openDetail() {
|
||||
router.push({
|
||||
@ -99,7 +116,7 @@ function openDetail() {
|
||||
--list-item-height: 64px;
|
||||
--list-item-border-radius: 8px;
|
||||
--list-item-gap: 10px;
|
||||
--list-item-padding: 20px;
|
||||
--list-item-padding: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@ -110,6 +127,25 @@ function openDetail() {
|
||||
&--offline {
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.row-left-box,
|
||||
.row-center-box,
|
||||
.row-right-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--list-item-gap);
|
||||
}
|
||||
|
||||
.row-left-box,
|
||||
.row-right-box {
|
||||
flex: 1;
|
||||
}
|
||||
.row-right-box {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.row-center-box {
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.list-column-item {
|
||||
@ -120,6 +156,7 @@ function openDetail() {
|
||||
&--server-flag {
|
||||
--server-flag-size: 24px;
|
||||
width: calc(var(--server-flag-size) * 1.5);
|
||||
margin-left: 20px;
|
||||
.server-flag {
|
||||
width: calc(var(--server-flag-size) * 1.5);
|
||||
height: var(--server-flag-size);
|
||||
@ -128,7 +165,7 @@ function openDetail() {
|
||||
}
|
||||
}
|
||||
&--server-name {
|
||||
flex: 1;
|
||||
width: 200px;
|
||||
|
||||
.server-name {
|
||||
height: 32px;
|
||||
@ -140,27 +177,5 @@ function openDetail() {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
&--server-system {
|
||||
width: 24px;
|
||||
justify-content: center;
|
||||
font-size: 24px;
|
||||
}
|
||||
&--cpu-mem {
|
||||
width: 100px;
|
||||
.core-mem {
|
||||
height: 30px;
|
||||
line-height: 32px;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 针对1440px以下的屏幕
|
||||
@media screen and (max-width: 1440px) {
|
||||
width: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -122,6 +122,44 @@ export default (params) => {
|
||||
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;
|
||||
});
|
||||
|
||||
/**
|
||||
* 计算入向网速
|
||||
*/
|
||||
@ -184,6 +222,22 @@ export default (params) => {
|
||||
unit: transfer.value?.unit,
|
||||
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':
|
||||
return {
|
||||
key,
|
||||
@ -226,7 +280,7 @@ export default (params) => {
|
||||
return {
|
||||
key,
|
||||
label: '负载',
|
||||
value: (props.info.State?.Load1 || 0).toFixed(2) * 1,
|
||||
value: (props.info.State?.Load1 || 0).toFixed(2),
|
||||
unit: '',
|
||||
show: validate.isSet(props.info.State?.Load1),
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user