优化首页,增加专区

This commit is contained in:
yml2213
2026-06-02 07:54:47 +08:00
parent 275294ed1c
commit 4509b22af7
+174 -3
View File
@@ -68,6 +68,7 @@ const filters = reactive({
maxFireLevel: undefined as number | undefined, maxFireLevel: undefined as number | undefined,
}); });
const sortBy = ref("recommended"); const sortBy = ref("recommended");
const activeZone = ref("all");
const coinRangeOptions = [ const coinRangeOptions = [
{ label: "全部区间", min: undefined, max: undefined }, { label: "全部区间", min: undefined, max: undefined },
@@ -128,6 +129,8 @@ const skinChipLabel = computed(() => {
const visibleListings = computed(() => { const visibleListings = computed(() => {
const keyword = filters.keyword.trim().toLowerCase(); const keyword = filters.keyword.trim().toLowerCase();
const filtered = listings.value.filter((item) => { const filtered = listings.value.filter((item) => {
if (!matchesZone(item, activeZone.value)) return false;
const text = [ const text = [
item.title, item.title,
item.description, item.description,
@@ -206,6 +209,45 @@ const statCards = computed(() => [
}, },
]); ]);
const zoneOptions = computed(() => [
{
key: "all",
label: "全部专区",
hint: "当前可租账号",
count: listings.value.length,
},
{
key: "sale",
label: "特惠专区",
hint: "价格更划算",
count: listings.value.filter((item) => matchesZone(item, "sale")).length,
},
{
key: "gift",
label: "赠送专区",
hint: "含赠送物品",
count: listings.value.filter((item) => matchesZone(item, "gift")).length,
},
{
key: "night",
label: "夜间专区",
hint: "夜间也好上号",
count: listings.value.filter((item) => matchesZone(item, "night")).length,
},
{
key: "password",
label: "账密专区",
hint: "交接更快",
count: listings.value.filter((item) => matchesZone(item, "password")).length,
},
{
key: "highCoin",
label: "高币专区",
hint: "100M 以上",
count: listings.value.filter((item) => matchesZone(item, "highCoin")).length,
},
]);
onMounted(loadHome); onMounted(loadHome);
async function loadHome() { async function loadHome() {
@@ -249,9 +291,14 @@ function resetFilters() {
filters.maxTotal = undefined; filters.maxTotal = undefined;
filters.minFireLevel = undefined; filters.minFireLevel = undefined;
filters.maxFireLevel = undefined; filters.maxFireLevel = undefined;
activeZone.value = "all";
sortBy.value = "recommended"; sortBy.value = "recommended";
} }
function setActiveZone(zoneKey: string) {
activeZone.value = zoneKey;
}
function uniqueOptions(values: string[]) { function uniqueOptions(values: string[]) {
return [...new Set(values.map((item) => item.trim()).filter(Boolean))]; return [...new Set(values.map((item) => item.trim()).filter(Boolean))];
} }
@@ -306,6 +353,40 @@ function resetSkinFilter() {
filters.skinGroup = ""; filters.skinGroup = "";
filters.skinName = ""; filters.skinName = "";
} }
function matchesZone(item: Listing, zoneKey: string) {
if (zoneKey === "all") return true;
if (zoneKey === "sale") return hasAcceleratedSaleRatio(item);
if (zoneKey === "gift") return hasGiftResources(item);
if (zoneKey === "night") return isNightAvailable(item);
if (zoneKey === "password") return /账密|账号密码/.test(getLoginMethod(item));
if (zoneKey === "highCoin") return getCoinM(item) >= 100;
return true;
}
function isNightAvailable(item: Listing) {
const onlineTime = item.asset_summary?.online_time;
if (typeof onlineTime !== "object" || onlineTime === null) return false;
const row = onlineTime as Record<string, unknown>;
const start = parseTimeHour(row.start);
const end = parseTimeHour(row.end);
if (start === undefined || end === undefined) return false;
return timeRangeCoversHour(start, end, 22) || timeRangeCoversHour(start, end, 23) || timeRangeCoversHour(start, end, 0);
}
function parseTimeHour(value: unknown) {
if (typeof value !== "string") return undefined;
const [hourText] = value.split(":");
const hour = Number(hourText);
if (!Number.isFinite(hour) || hour < 0 || hour > 23) return undefined;
return hour;
}
function timeRangeCoversHour(start: number, end: number, hour: number) {
if (start === end) return true;
if (start < end) return hour >= start && hour <= end;
return hour >= start || hour <= end;
}
</script> </script>
<template> <template>
@@ -667,9 +748,22 @@ function resetSkinFilter() {
<!-- 列表标题 & 排序 --> <!-- 列表标题 & 排序 -->
<div class="list-head"> <div class="list-head">
<div> <div class="zone-head">
<p class="eyebrow">Account Market</p> <p class="eyebrow">Account Zone</p>
<h2>可租账号推荐</h2> <h2>账号专区</h2>
<div class="zone-tabs">
<button
v-for="zone in zoneOptions"
:key="zone.key"
type="button"
:class="{ active: activeZone === zone.key }"
@click="setActiveZone(zone.key)"
>
<strong>{{ zone.label }}</strong>
<span>{{ zone.hint }}</span>
<em>{{ zone.count }}</em>
</button>
</div>
</div> </div>
<div class="list-actions"> <div class="list-actions">
<el-radio-group v-model="sortBy" size="small"> <el-radio-group v-model="sortBy" size="small">
@@ -1557,6 +1651,83 @@ function resetSkinFilter() {
color: #17233d; color: #17233d;
} }
.zone-head {
display: grid;
gap: 10px;
min-width: 0;
}
.zone-tabs {
display: flex;
flex-wrap: wrap;
gap: 10px;
max-width: 1120px;
}
.zone-tabs button {
position: relative;
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
gap: 2px 12px;
min-width: 132px;
min-height: 58px;
padding: 10px 14px;
border: 1px solid #eef1f5;
border-radius: 12px;
background: #ffffff;
color: #17233d;
text-align: left;
cursor: pointer;
transition: all 0.18s ease;
}
.zone-tabs button:hover {
border-color: rgba(255, 106, 0, 0.36);
box-shadow: 0 8px 20px rgba(23, 35, 61, 0.06);
transform: translateY(-1px);
}
.zone-tabs button.active {
border-color: #ff6a00;
background: #fff7ed;
box-shadow: 0 8px 20px rgba(255, 106, 0, 0.12);
}
.zone-tabs strong {
min-width: 0;
overflow: hidden;
color: inherit;
font-size: 15px;
font-weight: 900;
text-overflow: ellipsis;
white-space: nowrap;
}
.zone-tabs span {
grid-column: 1 / -1;
color: #8b9cb5;
font-size: 12px;
font-weight: 800;
}
.zone-tabs em {
align-self: start;
min-width: 24px;
border-radius: 999px;
background: #f1f5f9;
color: #64748b;
font-size: 12px;
font-style: normal;
font-weight: 900;
line-height: 22px;
text-align: center;
}
.zone-tabs button.active em {
background: #ff6a00;
color: #ffffff;
}
.eyebrow { .eyebrow {
margin: 0; margin: 0;
font-size: 12px; font-size: 12px;