row模式在移动端切换为card模式显示

This commit is contained in:
hi2hi 2024-12-18 04:04:23 +00:00
parent 836fddf860
commit d10386e6e9
7 changed files with 193 additions and 102 deletions

View File

@ -3,7 +3,7 @@ window.$$nazhuaConfig = {
// freeAmount: '白嫖', // 免费服务的费用名称
// infinityCycle: '长期有效', // 无限周期名称
// buyBtnText: '购买', // 购买按钮文案
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式目前为体验版不兼容移动端
// listServerItemType: 'row', // 服务器列表项类型 card/row row列表模式移动端自动切换至card
// listServerStatusType: 'progress', // 服务器状态类型--列表
// listServerRealTimeShowLoad: false, // 列表显示服务器实时负载
// detailServerStatusType: 'progress', // 服务器状态类型--详情页

View File

@ -21,6 +21,7 @@ const defaultState = () => ({
serverTime: 0,
serverGroup: [],
serverList: [],
serverListColumnWidths: {},
serverCount: {
total: 0,
online: 0,
@ -92,6 +93,9 @@ const store = createStore({
SET_SETTING(state, setting) {
state.setting = setting;
},
SET_SERVER_LIST_COLUMN_WIDTHS(state, widths) {
state.serverListColumnWidths = widths;
},
},
actions: {
/**
@ -184,6 +188,33 @@ 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);
},
},
});

View File

@ -4,7 +4,10 @@
:class="`list-column--${prop}`"
:style="columnStyle"
>
<div class="list-column-content">
<div
ref="columnContentRef"
class="list-column-content"
>
<span class="item-label">{{ label }}</span>
<div class="item-content">
<template v-if="slotContent">
@ -34,7 +37,13 @@
import {
computed,
ref,
onMounted,
onBeforeUnmount,
} from 'vue';
import {
useStore,
} from 'vuex';
const props = defineProps({
prop: {
@ -67,11 +76,46 @@ const props = defineProps({
},
});
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 = {};
const width = parseInt(props.width, 10);
if (Number.isNaN(width) === false) {
style.width = `${width}px`;
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;
});
@ -79,15 +123,23 @@ const columnStyle = computed(() => {
<style lang="scss" scoped>
.list-column {
width: 60px;
--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 {
--list-column-label-height: 16px;
--list-column-value-height: 24px;
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 {

View File

@ -3,7 +3,6 @@
v-if="extraFields?.remainingTime"
prop="remaining-time"
label="剩余"
:width="50"
:value="billAndPlan?.remainingTime?.value || '-'"
/>
<server-list-column
@ -16,7 +15,6 @@
v-if="extraFields?.orderLink"
prop="order-link"
label="链接"
:wdith="80"
:slot-content="true"
>
<span

View File

@ -6,7 +6,6 @@
:label="item.label"
:value="item.show ? item?.value : '-'"
:unit="item.show ? item?.unit : ''"
:width="fieldWidth[item.key]"
/>
</template>
@ -43,12 +42,4 @@ const {
currentTime,
serverRealTimeListTpls: props.serverRealTimeListTpls,
});
const fieldWidth = {
transfer: 80,
load: 40,
inSpeed: 40,
outSpeed: 40,
};
</script>

View File

@ -8,60 +8,52 @@
}"
@click="openDetail"
>
<div class="row-left-box">
<div class="list-column-item list-column-item--server-flag">
<div class="list-column-item list-column-item--server-flag">
<span
class="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'"
:width="40"
/>
<server-list-column
prop="server-system"
label="系统"
:value="platformSystemLabel || '-'"
/>
<server-list-column
prop="cpu-mem"
label="配置"
width="80"
:value="cpuAndMemAndDisk || '-'"
/>
class="fi"
:class="'fi-' + (info?.Host?.CountryCode || 'un')"
/>
</span>
</div>
<div class="row-center-box">
<server-list-item-status
v-if="$config.nazhua.hideListItemStatusDonut !== true"
:info="info"
/>
</div>
<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 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>
@ -116,8 +108,8 @@ function openDetail() {
.server-list-row-item {
--list-item-height: 64px;
--list-item-border-radius: 8px;
--list-item-gap: 10px;
--list-item-padding: 0;
--list-item-gap: 0;
--list-item-padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
@ -129,23 +121,8 @@ function openDetail() {
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;
@media (max-width: 1280px) {
--list-item-padding: 0 10px;
}
}
@ -157,13 +134,20 @@ 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);
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;
@ -177,6 +161,14 @@ function openDetail() {
white-space: nowrap;
overflow: hidden;
}
@media (max-width: 1280px) {
width: 180px;
}
@media (max-width: 1024px) {
width: 300px;
}
}
}
</style>

View File

@ -13,6 +13,10 @@
<div
v-if="showFilter"
class="fitler-group"
:class="{
'list-is-row': showListRow,
'list-is-card': showListCard,
}"
>
<div class="left-box">
<server-option-box
@ -30,13 +34,26 @@
</div>
</div>
<transition-group
v-if="showListRow"
name="list"
tag="div"
class="server-list-container"
:class="`server-list--${serverItemComponentName}`"
:class="`server-list--row`"
>
<component
:is="serverItemComponentMaps[serverItemComponentName]"
<server-row-item
v-for="item in filterServerList.list"
: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"
:info="item"
@ -76,17 +93,22 @@ import ServerOptionBox from './components/server-list/server-option-box.vue';
import ServerCardItem from './components/server-list/card/server-list-item.vue';
import ServerRowItem from './components/server-list/row/server-list-item.vue';
const serverItemComponentMaps = {
card: ServerCardItem,
row: ServerRowItem,
};
const serverItemComponentName = [
'card',
'row',
].includes(config.nazhua.listServerItemType) ? config.nazhua.listServerItemType : 'card';
const store = useStore();
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 filterFormData = ref({
@ -246,6 +268,7 @@ const showWorldMap = computed(() => {
*/
function handleResize() {
worldMapWidth.value = document.querySelector('.server-list-container').clientWidth - 40;
windowWidth.value = window.innerWidth;
}
onMounted(() => {
@ -285,6 +308,10 @@ onUnmounted(() => {
gap: 10px 20px;
width: var(--list-container-width);
margin: auto;
&.list-is-card {
padding: 0 20px;
}
}
.server-list-container.server-list--card {