优化了首页

This commit is contained in:
yml
2026-05-22 21:00:27 +08:00
parent aa9410b990
commit b050a8a1e7
3 changed files with 488 additions and 417 deletions
+2 -1
View File
@@ -19,7 +19,6 @@ declare module 'vue' {
VanCheckbox: typeof import('vant/es')['Checkbox']
VanDropdownItem: typeof import('vant/es')['DropdownItem']
VanDropdownMenu: typeof import('vant/es')['DropdownMenu']
VanEmpty: typeof import('vant/es')['Empty']
VanField: typeof import('vant/es')['Field']
VanGrid: typeof import('vant/es')['Grid']
VanGridItem: typeof import('vant/es')['GridItem']
@@ -27,8 +26,10 @@ declare module 'vue' {
VanImage: typeof import('vant/es')['Image']
VanLoading: typeof import('vant/es')['Loading']
VanNoticeBar: typeof import('vant/es')['NoticeBar']
VanPullRefresh: typeof import('vant/es')['PullRefresh']
VanSearch: typeof import('vant/es')['Search']
VanTabbar: typeof import('vant/es')['Tabbar']
VanTabbarItem: typeof import('vant/es')['TabbarItem']
VanTag: typeof import('vant/es')['Tag']
}
}
+353 -286
View File
@@ -1,15 +1,19 @@
<script setup lang="ts">
import { computed, onMounted, ref } from "vue";
import { RouterLink } from "vue-router";
import { RouterLink, useRoute } from "vue-router";
import { showToast } from "vant";
import { fetchListings, type Listing } from "@/api/listings";
const route = useRoute();
const loading = ref(false);
const loadFailed = ref(false);
const listings = ref<Listing[]>([]);
const filterOpen = ref(false);
const activeSort = ref(0);
const activeFilter = ref([]);
const activeFilter = ref<string[]>([]);
const activeChannel = ref(0);
const refreshing = ref(false);
const searchValue = ref("");
const channels = [
{ label: "全部", icon: "🔥" },
@@ -19,10 +23,10 @@ const channels = [
{ label: "包夜", icon: "🌙" },
];
const sortOptions = [
{ text: "默认", value: 0 },
{ text: "价格", value: 1 },
{ text: "比例", value: 2 },
{ text: "哈夫币", value: 3 },
{ text: "默认", value: "default" },
{ text: "价格", value: "price" },
{ text: "比例", value: "ratio" },
{ text: "哈夫币", value: "coin" },
];
const quickFilters = [
{ text: "三角洲行动", value: "a" },
@@ -121,12 +125,18 @@ const platformStats = computed(() => {
).length;
return [
{ value: `${items.length}+`, label: "在线租号" },
{ value: formatCoin(totalCoin), label: "哈夫币总量" },
{ value: `${lowDeposit}`, label: "低押账号" },
{ value: `${items.length}+`, label: "在线租号", icon: "👥" },
{ value: formatCoin(totalCoin), label: "哈夫币总量", icon: "💰" },
{ value: `${lowDeposit}`, label: "低押账号", icon: "🛡️" },
];
});
/** 判断当前底部导航是否激活 */
function isNavActive(path: string) {
if (path === "/m") return route.path === "/m";
return route.path.startsWith(path);
}
onMounted(loadListings);
async function loadListings() {
@@ -141,6 +151,27 @@ async function loadListings() {
}
}
async function onRefresh() {
refreshing.value = true;
try {
listings.value = await fetchListings();
showToast("刷新成功");
} catch {
// 静默处理
} finally {
refreshing.value = false;
}
}
function toggleFilter(value: string) {
const idx = activeFilter.value.indexOf(value);
if (idx >= 0) {
activeFilter.value.splice(idx, 1);
} else {
activeFilter.value.push(value);
}
}
function formatCoin(amount: number) {
if (amount >= 10000) {
return `${Math.round(amount / 10000)}W`;
@@ -154,13 +185,11 @@ function formatRatio(item: Listing) {
}
return `${Math.round(item.haf_coin_amount / item.price_hourly / 10000)}W/元`;
}
const searchValue = ref("");
</script>
<template>
<main class="mobile-shell">
<!-- 顶部品牌区 - 保留手写样式 -->
<!-- ========== Hero 区域纯色蓝色头部 ========== -->
<section class="mobile-hero">
<div class="mobile-topbar">
<div class="mobile-brand">
@@ -173,7 +202,6 @@ const searchValue = ref("");
<button class="mobile-service" type="button">客服</button>
</div>
<!-- 搜索栏 van-search -->
<van-search
v-model="searchValue"
shape="round"
@@ -181,142 +209,164 @@ const searchValue = ref("");
class="home-search"
/>
<!-- 防骗提示 van-notice-bar -->
<van-notice-bar
left-icon="warning"
scrollable
text="平台担保交易拒绝私下转账/共享验证码,交接全程留痕。"
class="fraud-notice"
/>
<div class="mobile-banner">
<div>
<p>三角洲行动账号专区</p>
<h1>高哈夫币 · 安全交接 · 随租随玩</h1>
<span>新人领券最高减 20 </span>
</div>
<div class="banner-badge">HOT</div>
<!-- 防骗提示卡片不用 van-notice-bar -->
<div class="fraud-tip">
<van-icon name="warning-o" :size="16" color="#b8860b" />
<span class="fraud-dot"></span>
<span>平台担保交易拒绝私下转账/共享验证码交接全程留痕</span>
</div>
</section>
<section class="mobile-content">
<!-- 频道按钮组 van-grid -->
<van-grid :column-num="5" :border="false" class="channel-grid">
<van-grid-item v-for="item in channels" :key="item.label">
<template #icon>
<span class="channel-icon">{{ item.icon }}</span>
</template>
<template #text>
<span class="channel-label">{{ item.label }}</span>
</template>
</van-grid-item>
</van-grid>
<!-- 数据背书面板 - 保留手写样式 -->
<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>
<!-- 排序/筛选 van-dropdown-menu -->
<van-dropdown-menu class="sort-dropdown">
<van-dropdown-item v-model="activeSort" :options="sortOptions" />
<van-dropdown-item
v-model="activeFilter"
:options="quickFilters"
title="筛选"
/>
</van-dropdown-menu>
<!-- 加载/错误状态 -->
<van-loading v-if="loading" class="state-loading" size="24px" vertical>
正在加载优质账号...
</van-loading>
<van-notice-bar
v-else-if="loadFailed"
left-icon="info-o"
color="#6b7a90"
background="transparent"
text="接口暂不可用,当前展示移动端示例数据。"
/>
<!-- 列表卡片 - 保留手写 mobile-card 样式 -->
<div class="mobile-list">
<RouterLink
v-for="item in displayListings"
:key="item.id"
class="mobile-card"
:to="`/m/listings/${item.id}`"
>
<div class="card-cover">
<span>{{ formatCoin(item.haf_coin_amount) }}</span>
<small>哈夫币</small>
<!-- ========== Content 区域 ========== -->
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<section class="mobile-content">
<!-- Banner 白色卡片 -->
<div class="mobile-banner">
<div>
<p>三角洲行动账号专区</p>
<h1>高哈夫币 · 安全交接 · 随租随玩</h1>
<span>新人领券最高减 20 </span>
</div>
<div class="card-body">
<div class="banner-badge">HOT</div>
</div>
<!-- 频道一体化条式布局 -->
<div class="channel-bar">
<div
v-for="(item, idx) in channels"
:key="item.label"
class="channel-item"
:class="{ active: activeChannel === idx }"
@click="activeChannel = idx"
>
<span class="channel-icon">{{ item.icon }}</span>
<span class="channel-text">{{ item.label }}</span>
</div>
</div>
<!-- 数据背书面板 -->
<div class="trust-panel" aria-label="交易数据背书">
<div v-for="item in platformStats" :key="item.label" class="trust-item">
<span class="trust-icon">{{ item.icon }}</span>
<strong>{{ item.value }}</strong>
<span>{{ item.label }}</span>
</div>
</div>
<!-- 排序van-tag 按钮组 -->
<div class="sort-bar">
<span
v-for="opt in sortOptions"
:key="opt.value"
class="sort-tag"
:class="{ active: activeSort === sortOptions.indexOf(opt) }"
@click="activeSort = sortOptions.indexOf(opt)"
>
{{ opt.text }}
</span>
</div>
<!-- 筛选van-tag 按钮组 -->
<div class="filter-bar">
<van-tag
v-for="f in quickFilters"
:key="f.value"
:type="activeFilter.includes(f.value) ? 'primary' : 'default'"
size="medium"
class="filter-tag"
@click="toggleFilter(f.value)"
>
{{ f.text }}
</van-tag>
</div>
<!-- 加载/错误状态 -->
<van-loading v-if="loading" class="state-loading" size="24px" vertical>
正在加载优质账号...
</van-loading>
<van-notice-bar
v-else-if="loadFailed"
left-icon="info-o"
color="#6b7a90"
background="transparent"
text="接口暂不可用,当前展示移动端示例数据。"
/>
<!-- 列表卡片全宽上下布局 -->
<div class="mobile-list">
<RouterLink
v-for="item in displayListings"
:key="item.id"
class="mobile-card"
:to="`/m/listings/${item.id}`"
>
<div class="card-title-row">
<h2>{{ item.title }}</h2>
<em>可租</em>
</div>
<p>
{{ item.server_region }} · {{ item.login_platform }} ·
{{ item.rank_level || "未填写段位" }}
</p>
<div class="card-tags">
<span>担保</span>
<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>
<van-tag type="primary" size="medium" plain>{{ item.server_region }}</van-tag>
<van-tag type="primary" size="medium" plain>{{ item.login_platform }}</van-tag>
<van-tag v-if="item.rank_level" type="primary" size="medium" plain>{{ item.rank_level }}</van-tag>
</div>
<div class="card-footer">
<strong>¥{{ item.price_hourly }}<small>/小时</small></strong>
<span
>日租 ¥{{ item.price_daily || "--" }} · 周租 ¥{{
item.price_weekly || "--"
}}</span
>
<div class="price-col">
<strong>¥{{ item.price_hourly }}<small>/小时</small></strong>
<span class="rent-sub">日租¥{{ item.price_daily || "--" }} · 周租¥{{ item.price_weekly || "--" }}</span>
</div>
<div class="coin-badge">
{{ formatCoin(item.haf_coin_amount) }}哈夫币
</div>
</div>
</div>
</RouterLink>
</div>
</section>
</RouterLink>
</div>
</section>
</van-pull-refresh>
<!-- 底部 TabBar van-tabbar route -->
<van-tabbar route class="home-tabbar">
<van-tabbar-item to="/m" icon="home-o">首页</van-tabbar-item>
<van-tabbar-item to="/m/listings" icon="search">租号</van-tabbar-item>
<van-tabbar-item to="/m/seller/listings/create" icon="add-o" class="tabbar-publish">发布</van-tabbar-item>
<van-tabbar-item to="/m/orders" icon="orders-o">订单</van-tabbar-item>
<van-tabbar-item to="/m/profile" icon="manager-o">我的</van-tabbar-item>
</van-tabbar>
<!-- ========== 底部导航原生App风格手写不用 van-tabbar ========== -->
<nav class="bottom-nav">
<RouterLink to="/m" class="nav-item" :class="{ active: isNavActive('/m') }">
<van-icon name="home-o" :size="22" />
<span>首页</span>
</RouterLink>
<RouterLink to="/m/listings" class="nav-item" :class="{ active: isNavActive('/m/listings') }">
<van-icon name="search" :size="22" />
<span>租号</span>
</RouterLink>
<RouterLink to="/m/seller/listings/create" class="nav-item nav-publish">
<div class="publish-pill">+</div>
<span>发布</span>
</RouterLink>
<RouterLink to="/m/orders" class="nav-item" :class="{ active: isNavActive('/m/orders') }">
<van-icon name="orders-o" :size="22" />
<span>订单</span>
</RouterLink>
<RouterLink to="/m/profile" class="nav-item" :class="{ active: isNavActive('/m/profile') }">
<van-icon name="manager-o" :size="22" />
<span>我的</span>
</RouterLink>
</nav>
</main>
</template>
<style scoped>
.mobile-shell {
min-height: 100vh;
background: #eef5ff;
background: #f5f7fa;
color: #17233d;
padding-bottom: 92px;
padding-bottom: 58px;
}
/* ========== Hero 区域 ========== */
/* ========== Hero 区域:纯色蓝色头部 ========== */
.mobile-hero {
overflow: hidden;
border-radius: 0 0 28px 28px;
background: linear-gradient(180deg, #1479ff 0%, #0b66e4 61%, #eef5ff 61%);
padding: 14px 14px 0;
border-radius: 0 0 24px 24px;
background: #1479ff;
padding: 14px 14px 18px;
}
.mobile-topbar,
.mobile-brand,
.card-title-row,
.card-footer {
.mobile-brand {
display: flex;
align-items: center;
}
@@ -370,7 +420,6 @@ const searchValue = ref("");
.home-search :deep(.van-search__content) {
border-radius: 999px;
background: #ffffff;
box-shadow: 0 10px 24px rgba(0, 54, 135, 0.12);
padding: 8px 14px;
}
@@ -379,30 +428,43 @@ const searchValue = ref("");
font-size: 14px;
}
/* ========== van-notice-bar 防骗提示 ========== */
.fraud-notice {
/* ========== 防骗提示卡片 ========== */
.fraud-tip {
display: flex;
align-items: center;
gap: 8px;
margin-top: 12px;
border-radius: 12px;
background: #ffe27a;
color: #5c3b00;
background: #ffffff;
padding: 10px 14px;
font-size: 12px;
line-height: 1.45;
}
.fraud-notice :deep(.van-notice-bar__left-icon) {
color: #5c3b00;
}
/* ========== Banner ========== */
.fraud-dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: #f0a500;
flex-shrink: 0;
}
/* ========== Content 区 ========== */
.mobile-content {
padding: 14px;
}
/* ========== Banner 白色卡片 ========== */
.mobile-banner {
display: flex;
justify-content: space-between;
gap: 14px;
margin-top: 14px;
border-radius: 20px;
background: linear-gradient(135deg, #ffffff, #dcecff);
border-radius: 16px;
background: #ffffff;
padding: 18px;
box-shadow: 0 14px 34px rgba(20, 121, 255, 0.18);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
.mobile-banner p,
@@ -444,36 +506,52 @@ const searchValue = ref("");
transform: rotate(8deg);
}
/* ========== Content 区 ========== */
.mobile-content {
padding: 14px;
}
/* ========== van-grid 频道 ========== */
.channel-grid {
margin-top: 0;
}
.channel-grid :deep(.van-grid-item__content) {
padding: 11px 6px;
background: #ffffff;
/* ========== 频道:一体化条式布局 ========== */
.channel-bar {
display: flex;
margin-top: 12px;
border-radius: 16px;
box-shadow: 0 8px 22px rgba(23, 35, 61, 0.06);
background: #ffffff;
padding: 6px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
.channel-grid :deep(.van-grid-item__content--surround::after) {
display: none;
.channel-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
padding: 8px 0;
border-radius: 12px;
cursor: pointer;
transition: all 0.2s;
}
.channel-item.active {
background: #1479ff;
color: #ffffff;
}
.channel-item.active .channel-icon,
.channel-item.active .channel-text {
color: #ffffff;
}
.channel-icon {
font-size: 22px;
font-size: 18px;
line-height: 1;
}
.channel-label {
font-size: 12px;
.channel-text {
font-size: 11px;
font-weight: 700;
color: #5a6577;
}
.channel-item.active .channel-text {
color: #ffffff;
font-weight: 800;
color: #24324a;
}
/* ========== 数据背书面板 ========== */
@@ -482,53 +560,77 @@ const searchValue = ref("");
grid-template-columns: repeat(3, 1fr);
gap: 8px;
margin-top: 12px;
border-radius: 18px;
border-radius: 16px;
background: #ffffff;
padding: 12px 10px;
box-shadow: 0 8px 22px rgba(23, 35, 61, 0.06);
padding: 14px 10px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}
.trust-panel div {
.trust-item {
text-align: center;
}
.trust-panel strong,
.trust-panel span {
.trust-icon {
font-size: 16px;
line-height: 1;
}
.trust-item strong,
.trust-item span {
display: block;
}
.trust-panel strong {
color: #1479ff;
.trust-item strong {
margin-top: 6px;
color: #1477ff;
font-size: 17px;
font-weight: 900;
}
.trust-panel span {
.trust-item span {
margin-top: 4px;
color: #7b8799;
font-size: 11px;
}
/* ========== van-dropdown-menu 排序筛选 ========== */
.sort-dropdown {
margin: 12px -14px 0;
border-radius: 0;
/* ========== 排序 van-tag 按钮组 ========== */
.sort-bar {
display: flex;
gap: 8px;
margin-top: 12px;
}
.sort-dropdown :deep(.van-dropdown-menu__bar) {
background: rgba(238, 245, 255, 0.92);
backdrop-filter: blur(12px);
box-shadow: none;
.sort-tag {
display: inline-flex;
align-items: center;
border-radius: 999px;
padding: 6px 14px;
font-size: 13px;
font-weight: 600;
color: #5a6577;
background: #ffffff;
border: 1px solid #e8ecf1;
cursor: pointer;
transition: all 0.2s;
}
.sort-dropdown :deep(.van-dropdown-menu__title) {
font-weight: 800;
color: #4d5b73;
font-size: 14px;
.sort-tag.active {
background: #1479ff;
color: #ffffff;
border-color: #1479ff;
}
.sort-dropdown :deep(.van-dropdown-menu__title--active) {
color: #1479ff;
/* ========== 筛选 van-tag 按钮组 ========== */
.filter-bar {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-top: 10px;
}
.filter-tag {
cursor: pointer;
user-select: none;
}
/* ========== 加载状态 ========== */
@@ -548,40 +650,18 @@ const searchValue = ref("");
}
.mobile-card {
display: grid;
grid-template-columns: 92px 1fr;
gap: 12px;
border-radius: 18px;
background: #ffffff;
padding: 12px;
box-shadow: 0 10px 26px rgba(23, 35, 61, 0.07);
}
.card-cover {
display: grid;
min-height: 116px;
place-content: center;
display: block;
border-radius: 16px;
background: linear-gradient(145deg, #126cff, #63b3ff);
color: #ffffff;
text-align: center;
}
.card-cover span {
font-size: 24px;
font-weight: 900;
}
.card-cover small {
margin-top: 2px;
font-size: 12px;
}
.card-body {
min-width: 0;
background: #ffffff;
padding: 14px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
text-decoration: none;
color: inherit;
}
.card-title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
}
@@ -593,6 +673,8 @@ const searchValue = ref("");
line-height: 1.35;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1;
min-width: 0;
}
.card-title-row em {
@@ -606,111 +688,96 @@ const searchValue = ref("");
font-weight: 800;
}
.card-body p {
overflow: hidden;
margin: 7px 0 0;
color: #6b7a90;
font-size: 12px;
text-overflow: ellipsis;
white-space: nowrap;
}
.card-tags,
.asset-row {
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 5px;
margin-top: 8px;
}
.card-tags span {
border-radius: 6px;
background: #f0f6ff;
color: #1479ff;
padding: 3px 5px;
font-size: 11px;
}
.asset-row span {
color: #6f7c90;
font-size: 11px;
gap: 6px;
margin-top: 10px;
}
.card-footer {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 8px;
margin-top: 9px;
margin-top: 12px;
}
.price-col {
display: flex;
flex-direction: column;
gap: 2px;
}
.card-footer strong {
flex: 0 0 auto;
color: #ff5f00;
font-size: 18px;
}
.card-footer small,
.card-footer span {
.card-footer .rent-sub {
color: #8a96a8;
font-size: 11px;
font-weight: 500;
}
.card-footer span {
overflow: hidden;
text-align: right;
text-overflow: ellipsis;
white-space: nowrap;
}
/* ========== van-tabbar 底部导航 ========== */
.home-tabbar {
position: fixed;
right: 12px;
bottom: 12px;
left: 12px;
z-index: 20;
height: 60px;
border-radius: 22px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 16px 36px rgba(23, 35, 61, 0.16);
backdrop-filter: blur(14px);
padding: 0;
}
.home-tabbar :deep(.van-tabbar) {
border-radius: 22px;
height: 60px;
}
.home-tabbar :deep(.van-tabbar-item) {
color: #708097;
.coin-badge {
display: inline-flex;
align-items: center;
border-radius: 999px;
background: #e8f0ff;
color: #1477ff;
padding: 4px 10px;
font-size: 12px;
font-weight: 800;
font-weight: 700;
}
.home-tabbar :deep(.van-tabbar-item--active) {
color: #1479ff;
/* ========== 底部导航:原生App风格 ========== */
.bottom-nav {
position: fixed;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
display: flex;
height: 50px;
background: #fff;
border-top: 1px solid #eee;
}
.home-tabbar :deep(.van-tabbar-item__icon) {
font-size: 20px;
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
color: #999;
font-size: 10px;
text-decoration: none;
}
/* 发布按钮特殊样式 */
.tabbar-publish :deep(.van-tabbar-item__icon) {
.nav-item.active {
color: #1477ff;
}
.nav-item span {
font-weight: 600;
}
.publish-pill {
width: 36px;
height: 26px;
display: grid;
width: 48px;
height: 48px;
place-items: center;
border-radius: 50%;
background: linear-gradient(180deg, #ffb21a, #ff6a00);
color: #ffffff !important;
font-size: 22px;
transform: translateY(-8px);
box-shadow: 0 8px 20px rgba(255, 106, 0, 0.35);
border-radius: 13px;
background: #ff6a00;
color: #fff;
font-size: 18px;
font-weight: 900;
}
.tabbar-publish :deep(.van-tabbar-item__text) {
.nav-publish span {
color: #ff6a00;
}
@@ -722,9 +789,9 @@ const searchValue = ref("");
box-shadow: 0 0 0 1px rgba(23, 35, 61, 0.08);
}
.home-tabbar {
right: calc((100vw - 430px) / 2 + 12px);
left: calc((100vw - 430px) / 2 + 12px);
.bottom-nav {
left: calc((100vw - 430px) / 2);
right: calc((100vw - 430px) / 2);
}
}
</style>
+133 -130
View File
@@ -36,36 +36,26 @@ function goToLogin() {
<template>
<main class="mobile-profile-shell">
<!-- 未登录区 van-empty + van-button -->
<!-- 未登录区 - 自定义卡片布局 -->
<template v-if="!isLoggedIn">
<section class="guest-section">
<van-empty
image="error"
description="登录后查看订单、管理发布、提现余额"
class="guest-empty"
>
<template #image>
<div class="guest-logo"></div>
</template>
</van-empty>
<van-button
type="primary"
block
round
class="guest-login-btn"
@click="goToLogin"
>
<section class="guest-card">
<div class="guest-logo"></div>
<h1>登录大锤商行</h1>
<p>登录后查看订单管理发布提现余额并享受平台担保交易服务</p>
<van-button type="primary" block round class="guest-login-btn" @click="goToLogin">
立即登录
</van-button>
<div class="guest-benefits">
<span>担保交易</span><span>订单留痕</span><span>安全交接</span>
<van-tag type="primary" plain size="medium" round>担保交易</van-tag>
<van-tag type="primary" plain size="medium" round>订单留痕</van-tag>
<van-tag type="primary" plain size="medium" round>安全交接</van-tag>
</div>
</section>
</template>
<!-- 已登录区 -->
<template v-else>
<!-- 头像区 van-cell + van-image -->
<!-- 头像区 -->
<section class="profile-header">
<van-image
round
@@ -85,38 +75,28 @@ function goToLogin() {
<van-icon name="setting-o" size="24" class="setting-icon" />
</section>
<!-- 余额卡片 van-cell-group + van-cell -->
<!-- 余额卡片 - 两行结构 -->
<van-cell-group inset class="balance-group">
<van-cell center>
<van-cell center class="balance-main">
<template #title>
<div class="balance-info">
<span class="balance-label">账户余额()</span>
<strong class="balance-value">¥0.00</strong>
<van-button
size="mini"
plain
hairline
type="warning"
class="detail-btn"
>
查看明细
</van-button>
</div>
<span class="balance-label">账户余额()</span>
</template>
<template #value>
<van-button
type="primary"
size="small"
class="withdraw-btn"
>
提现
</van-button>
<strong class="balance-value">¥0.00</strong>
</template>
</van-cell>
<van-cell class="balance-actions">
<template #title>
<van-button size="mini" plain hairline type="warning" class="detail-btn">查看明细</van-button>
</template>
<template #value>
<van-button type="primary" size="small" round class="withdraw-btn">提现</van-button>
</template>
</van-cell>
</van-cell-group>
</template>
<!-- 订单菜单 van-grid -->
<!-- 订单菜单 -->
<section class="menu-section">
<h2>我的订单</h2>
<van-grid :column-num="4" :border="false" class="order-grid">
@@ -135,7 +115,7 @@ function goToLogin() {
</van-grid>
</section>
<!-- 我买的 van-grid -->
<!-- 我买的 -->
<section class="menu-section">
<h2>我买的</h2>
<van-grid :column-num="4" :border="false" class="order-grid">
@@ -154,7 +134,7 @@ function goToLogin() {
</van-grid>
</section>
<!-- 服务菜单 van-grid -->
<!-- 服务菜单 -->
<van-cell-group inset class="service-group">
<van-grid :column-num="4" :border="false" class="service-grid">
<van-grid-item
@@ -171,7 +151,7 @@ function goToLogin() {
</van-grid>
</van-cell-group>
<!-- 退出登录 van-button -->
<!-- 退出登录 -->
<van-button
v-if="isLoggedIn"
plain
@@ -183,60 +163,82 @@ function goToLogin() {
退出登录
</van-button>
<!-- 底部 TabBar van-tabbar route -->
<van-tabbar route class="profile-tabbar">
<van-tabbar-item to="/m" icon="home-o">首页</van-tabbar-item>
<van-tabbar-item to="/m/listings" icon="search">租号</van-tabbar-item>
<van-tabbar-item to="/m/seller/listings/create" icon="add-o" class="tabbar-publish">发布</van-tabbar-item>
<van-tabbar-item to="/m/orders" icon="orders-o">订单</van-tabbar-item>
<van-tabbar-item to="/m/profile" icon="manager-o">我的</van-tabbar-item>
</van-tabbar>
<!-- 底部导航 - 手写原生和首页一致 -->
<nav class="bottom-nav">
<RouterLink to="/m" class="nav-item">
<van-icon name="home-o" :size="22" />
<span>首页</span>
</RouterLink>
<RouterLink to="/m/listings" class="nav-item">
<van-icon name="search" :size="22" />
<span>租号</span>
</RouterLink>
<RouterLink to="/m/seller/listings/create" class="nav-item nav-publish">
<div class="publish-pill">+</div>
<span>发布</span>
</RouterLink>
<RouterLink to="/m/orders" class="nav-item">
<van-icon name="orders-o" :size="22" />
<span>订单</span>
</RouterLink>
<RouterLink to="/m/profile" class="nav-item active">
<van-icon name="manager-o" :size="22" />
<span>我的</span>
</RouterLink>
</nav>
</main>
</template>
<style scoped>
.mobile-profile-shell {
min-height: 100vh;
background: linear-gradient(180deg, #fbfaff 0, #fbfaff 210px, #f7f7f7 210px);
background: #f5f6f8;
color: #1a202c;
padding: 28px 12px 96px;
padding: 28px 12px 60px;
}
/* ========== 未登录区 ========== */
.guest-section {
/* ========== 未登录区 - 自定义卡片 ========== */
.guest-card {
text-align: center;
padding: 20px 14px 0;
padding: 34px 26px;
margin: 0 2px;
border-radius: 16px;
background: #fff;
box-shadow: 0 8px 26px rgba(24, 30, 45, 0.06);
}
.guest-empty {
padding: 0;
.guest-card h1 {
margin: 18px 0 0;
font-size: 22px;
font-weight: 900;
color: #1a202c;
}
.guest-empty :deep(.van-empty__description) {
color: #667386;
.guest-card p {
margin: 10px 0 0;
font-size: 14px;
color: #667386;
line-height: 1.7;
margin-top: 12px;
}
.guest-logo {
display: grid;
width: 74px;
height: 74px;
margin: 0 auto 0;
margin: 0 auto;
place-items: center;
border-radius: 22px;
background: linear-gradient(145deg, #1777ff, #5ed7ff);
background: #1477ff;
color: #fff;
font-size: 30px;
font-weight: 900;
}
.guest-login-btn {
margin-top: 18px;
margin-top: 20px;
border-radius: 13px;
background: #050505;
border-color: #050505;
background: #1477ff;
border-color: transparent;
font-size: 16px;
font-weight: 900;
height: 48px;
@@ -249,12 +251,7 @@ function goToLogin() {
margin-top: 16px;
}
.guest-benefits span {
border-radius: 999px;
background: #eef6ff;
color: #1777ff;
padding: 6px 9px;
font-size: 12px;
.guest-benefits :deep(.van-tag) {
font-weight: 800;
}
@@ -311,7 +308,7 @@ function goToLogin() {
cursor: pointer;
}
/* ========== 余额卡片 ========== */
/* ========== 余额卡片 - 两行结构 ========== */
.balance-group {
margin-top: 10px;
border-radius: 16px;
@@ -319,14 +316,13 @@ function goToLogin() {
box-shadow: 0 8px 26px rgba(24, 30, 45, 0.06);
}
.balance-group :deep(.van-cell) {
padding: 24px 20px;
.balance-main :deep(.van-cell__title) {
flex: none;
}
.balance-info {
display: flex;
flex-direction: column;
gap: 0;
.balance-main :deep(.van-cell__value) {
flex: 1;
text-align: right;
}
.balance-label {
@@ -336,15 +332,26 @@ function goToLogin() {
}
.balance-value {
margin-top: 10px;
font-size: 34px;
font-size: 32px;
line-height: 1;
color: #1a202c;
}
.balance-actions {
padding-top: 4px !important;
padding-bottom: 12px !important;
}
.balance-actions :deep(.van-cell__title) {
flex: none;
}
.balance-actions :deep(.van-cell__value) {
flex: 1;
text-align: right;
}
.detail-btn {
margin-top: 10px;
align-self: flex-start;
border-color: #ff8a42;
color: #ff5f00;
background: #fff5ee;
@@ -352,12 +359,11 @@ function goToLogin() {
}
.withdraw-btn {
background: #050505;
border-color: #050505;
border-radius: 6px;
padding: 12px 18px;
background: #1477ff;
border-color: transparent;
font-weight: 800;
height: auto;
height: 32px;
padding: 0 20px;
}
/* ========== 订单菜单 ========== */
@@ -416,55 +422,52 @@ function goToLogin() {
font-size: 16px;
}
/* ========== van-tabbar 底部导航 ========== */
.profile-tabbar {
/* ========== 底部导航 - 手写原生 ========== */
.bottom-nav {
position: fixed;
right: 12px;
bottom: 12px;
left: 12px;
z-index: 20;
height: 60px;
border-radius: 22px;
background: rgba(255, 255, 255, 0.96);
box-shadow: 0 16px 36px rgba(23, 35, 61, 0.16);
backdrop-filter: blur(14px);
padding: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 100;
display: flex;
height: 50px;
background: #fff;
border-top: 1px solid #eee;
}
.profile-tabbar :deep(.van-tabbar) {
border-radius: 22px;
height: 60px;
.nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
color: #999;
font-size: 10px;
text-decoration: none;
}
.profile-tabbar :deep(.van-tabbar-item) {
color: #708097;
font-size: 12px;
font-weight: 800;
.nav-item.active {
color: #1477ff;
}
.profile-tabbar :deep(.van-tabbar-item--active) {
color: #5b6ee1;
.nav-item span {
font-weight: 600;
}
.profile-tabbar :deep(.van-tabbar-item__icon) {
font-size: 20px;
}
/* 发布按钮特殊样式 */
.tabbar-publish :deep(.van-tabbar-item__icon) {
.publish-pill {
width: 36px;
height: 26px;
display: grid;
width: 48px;
height: 48px;
place-items: center;
border-radius: 50%;
background: linear-gradient(180deg, #ffb21a, #ff6a00);
color: #ffffff !important;
font-size: 22px;
transform: translateY(-8px);
box-shadow: 0 8px 20px rgba(255, 106, 0, 0.35);
border-radius: 13px;
background: #ff6a00;
color: #fff;
font-size: 18px;
font-weight: 900;
}
.tabbar-publish :deep(.van-tabbar-item__text) {
.nav-publish span {
color: #ff6a00;
}
@@ -476,9 +479,9 @@ function goToLogin() {
box-shadow: 0 0 0 1px rgba(23, 35, 61, 0.08);
}
.profile-tabbar {
right: calc((100vw - 430px) / 2 + 12px);
left: calc((100vw - 430px) / 2 + 12px);
.bottom-nav {
left: calc((100vw - 430px) / 2);
right: calc((100vw - 430px) / 2);
}
}
</style>