[Snow Team] mobile-ui-mvp: auto-commit work

This commit is contained in:
yml
2026-05-22 19:25:57 +08:00
parent 37cf2729be
commit 83c35e0932
+178 -63
View File
@@ -8,9 +8,16 @@ const loading = ref(false)
const loadFailed = ref(false)
const listings = ref<Listing[]>([])
const filterOpen = ref(false)
const activeSort = ref('推荐')
const activeSort = ref('默认')
const sortOptions = ['推荐', '低价', '高哈夫币', '免押优先']
const channels = [
{ label: '全部', icon: '🔥' },
{ label: '高哈夫币', icon: '💰' },
{ label: '低押金', icon: '🛡️' },
{ label: '扫码号', icon: '📱' },
{ label: '包夜', icon: '🌙' },
]
const sortOptions = ['默认', '价格', '比例', '哈夫币', '筛选']
const quickFilters = ['三角洲行动', '安卓/扫码', '高段位', '可包夜']
const fallbackListings: Listing[] = [
@@ -90,6 +97,18 @@ const fallbackListings: Listing[] = [
const displayListings = computed(() => (listings.value.length > 0 ? listings.value : fallbackListings))
const platformStats = computed(() => {
const items = displayListings.value
const totalCoin = items.reduce((sum, item) => sum + Number(item.haf_coin_amount || 0), 0)
const lowDeposit = items.filter((item) => Number(item.deposit_amount || 0) <= 120).length
return [
{ value: `${items.length}+`, label: '在线租号' },
{ value: formatCoin(totalCoin), label: '哈夫币总量' },
{ value: `${lowDeposit}`, label: '低押账号' },
]
})
onMounted(loadListings)
async function loadListings() {
@@ -110,6 +129,13 @@ function formatCoin(amount: number) {
}
return `${amount}`
}
function formatRatio(item: Listing) {
if (!item.price_hourly) {
return '--'
}
return `${Math.round(item.haf_coin_amount / item.price_hourly / 10000)}W/元`
}
</script>
<template>
@@ -126,16 +152,16 @@ function formatCoin(amount: number) {
<button class="mobile-service" type="button">客服</button>
</div>
<label class="mobile-search">
<span>🔍</span>
<input type="search" placeholder="搜区服 / 段位 / 哈夫币数量" />
</label>
<div class="fraud-alert">
<span>防骗提示</span>
平台担保交易拒绝私下转账/共享验证码交接全程留痕
</div>
<label class="mobile-search">
<span>🔍</span>
<input type="search" placeholder="搜索区服 / 段位 / 哈夫币数量" />
</label>
<div class="mobile-banner">
<div>
<p>三角洲行动账号专区</p>
@@ -147,27 +173,36 @@ function formatCoin(amount: number) {
</section>
<section class="mobile-content">
<button class="filter-entry" type="button" @click="filterOpen = !filterOpen">
<span>高级筛选</span>
<strong>{{ filterOpen ? '收起' : '展开' }}</strong>
</button>
<div v-if="filterOpen" class="filter-panel">
<button v-for="item in quickFilters" :key="item" type="button">{{ item }}</button>
<div class="channel-strip" aria-label="快捷频道">
<button v-for="item in channels" :key="item.label" type="button">
<span>{{ item.icon }}</span>
{{ item.label }}
</button>
</div>
<div class="sort-pills" aria-label="排序方式">
<div class="trust-panel" aria-label="交易数据背书">
<div v-for="item in platformStats" :key="item.label">
<strong>{{ item.value }}</strong>
<span>{{ item.label }}</span>
</div>
</div>
<div class="sort-bar" aria-label="排序方式">
<button
v-for="item in sortOptions"
:key="item"
:class="{ active: activeSort === item }"
type="button"
@click="activeSort = item"
@click="item === '筛选' ? (filterOpen = !filterOpen) : (activeSort = item)"
>
{{ item }}
{{ item }}<span v-if="item === '筛选'"></span>
</button>
</div>
<div v-if="filterOpen" class="filter-panel">
<button v-for="item in quickFilters" :key="item" type="button">{{ item }}</button>
</div>
<p v-if="loadFailed" class="mobile-tip">接口暂不可用当前展示移动端示例数据</p>
<p v-else-if="loading" class="mobile-tip">正在加载优质账号...</p>
@@ -188,9 +223,14 @@ function formatCoin(amount: number) {
<span>秒接单</span>
<span>{{ item.min_rent_hours }}小时起租</span>
</div>
<div class="asset-row">
<span>哈夫币 {{ formatCoin(item.haf_coin_amount) }}</span>
<span>比例 {{ formatRatio(item) }}</span>
<span>押金 ¥{{ item.deposit_amount }}</span>
</div>
<div class="card-footer">
<strong>¥{{ item.price_hourly }}<small>/小时</small></strong>
<span>押金 ¥{{ item.deposit_amount }}</span>
<span>日租 ¥{{ item.price_daily || '--' }} · 周租 ¥{{ item.price_weekly || '--' }}</span>
</div>
</div>
</RouterLink>
@@ -218,7 +258,7 @@ function formatCoin(amount: number) {
.mobile-hero {
overflow: hidden;
border-radius: 0 0 28px 28px;
background: linear-gradient(180deg, #1479ff 0%, #0b66e4 58%, #eef5ff 58%);
background: linear-gradient(180deg, #1479ff 0%, #0b66e4 61%, #eef5ff 61%);
padding: 14px 14px 0;
}
@@ -270,21 +310,6 @@ function formatCoin(amount: number) {
padding: 7px 12px;
}
.fraud-alert {
margin-top: 14px;
border-radius: 12px;
background: #ffe27a;
color: #5c3b00;
padding: 10px 12px;
font-size: 12px;
line-height: 1.45;
}
.fraud-alert span {
margin-right: 6px;
font-weight: 800;
}
.mobile-search {
display: flex;
align-items: center;
@@ -305,6 +330,21 @@ function formatCoin(amount: number) {
font-size: 14px;
}
.fraud-alert {
margin-top: 12px;
border-radius: 12px;
background: #ffe27a;
color: #5c3b00;
padding: 10px 12px;
font-size: 12px;
line-height: 1.45;
}
.fraud-alert span {
margin-right: 6px;
font-weight: 800;
}
.mobile-banner {
display: flex;
justify-content: space-between;
@@ -359,48 +399,108 @@ function formatCoin(amount: number) {
padding: 14px;
}
.filter-entry {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
border: 0;
border-radius: 16px;
background: #ffffff;
color: #17233d;
padding: 14px;
font-size: 15px;
box-shadow: 0 8px 22px rgba(23, 35, 61, 0.06);
}
.filter-entry strong {
color: #1479ff;
}
.filter-panel,
.sort-pills {
.channel-strip,
.sort-bar,
.filter-panel {
display: flex;
gap: 8px;
overflow-x: auto;
padding: 10px 0 2px;
padding-bottom: 2px;
scrollbar-width: none;
}
.filter-panel button,
.sort-pills button {
.channel-strip::-webkit-scrollbar,
.sort-bar::-webkit-scrollbar,
.filter-panel::-webkit-scrollbar {
display: none;
}
.channel-strip button {
display: grid;
min-width: 72px;
gap: 4px;
flex: 0 0 auto;
place-items: center;
border: 0;
border-radius: 16px;
background: #ffffff;
color: #24324a;
padding: 11px 12px;
font-size: 12px;
font-weight: 800;
box-shadow: 0 8px 22px rgba(23, 35, 61, 0.06);
}
.channel-strip span {
font-size: 18px;
}
.trust-panel {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
margin-top: 12px;
border-radius: 18px;
background: #ffffff;
padding: 12px 10px;
box-shadow: 0 8px 22px rgba(23, 35, 61, 0.06);
}
.trust-panel div {
text-align: center;
}
.trust-panel strong,
.trust-panel span {
display: block;
}
.trust-panel strong {
color: #1479ff;
font-size: 17px;
font-weight: 900;
}
.trust-panel span {
margin-top: 4px;
color: #7b8799;
font-size: 11px;
}
.sort-bar {
position: sticky;
top: 0;
z-index: 10;
margin: 12px -14px 0;
background: rgba(238, 245, 255, 0.92);
padding: 10px 14px 8px;
backdrop-filter: blur(12px);
}
.filter-panel {
padding: 8px 0 2px;
}
.sort-bar button,
.filter-panel button {
flex: 0 0 auto;
border: 0;
border-radius: 999px;
background: #ffffff;
color: #4d5b73;
padding: 9px 12px;
font-weight: 700;
font-weight: 800;
}
.sort-pills button.active {
.sort-bar button.active {
background: #1479ff;
color: #ffffff;
}
.sort-bar button span {
margin-left: 2px;
}
.mobile-tip {
margin: 12px 2px;
color: #6b7a90;
@@ -425,7 +525,7 @@ function formatCoin(amount: number) {
.card-cover {
display: grid;
min-height: 104px;
min-height: 116px;
place-content: center;
border-radius: 16px;
background: linear-gradient(145deg, #126cff, #63b3ff);
@@ -481,11 +581,12 @@ function formatCoin(amount: number) {
white-space: nowrap;
}
.card-tags {
.card-tags,
.asset-row {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 9px;
margin-top: 8px;
}
.card-tags span {
@@ -496,12 +597,19 @@ function formatCoin(amount: number) {
font-size: 11px;
}
.asset-row span {
color: #6f7c90;
font-size: 11px;
}
.card-footer {
justify-content: space-between;
margin-top: 11px;
gap: 8px;
margin-top: 9px;
}
.card-footer strong {
flex: 0 0 auto;
color: #ff5f00;
font-size: 18px;
}
@@ -513,6 +621,13 @@ function formatCoin(amount: number) {
font-weight: 500;
}
.card-footer span {
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
}
.mobile-tabbar {
position: fixed;
right: 12px;