新增行列的单独组件

This commit is contained in:
hi2hi 2024-12-14 06:28:54 +00:00
parent 5ec81d7616
commit 3501483af0
5 changed files with 331 additions and 220 deletions

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

View File

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

View File

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

View File

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

View File

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