style(mobile): 优化个人中心和站内信界面

This commit is contained in:
yml2213
2026-11-04 20:15:22 +08:00
parent 90b83972ec
commit aeda6f4cd3
4 changed files with 455 additions and 169 deletions
+2 -1
View File
@@ -4,7 +4,8 @@
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vue-tsc -b --noEmit --watch --preserveWatchOutput & vite --host 0.0.0.0", "dev": "vite --host 0.0.0.0",
"dev:typecheck": "vue-tsc -b --noEmit --watch --preserveWatchOutput",
"build": "vue-tsc -b --noEmit && vite build", "build": "vue-tsc -b --noEmit && vite build",
"preview": "vite preview --host 0.0.0.0", "preview": "vite preview --host 0.0.0.0",
"typecheck": "vue-tsc -b --noEmit", "typecheck": "vue-tsc -b --noEmit",
@@ -93,6 +93,30 @@ function typeLabel(type: string) {
} }
return map[type] || '系统' return map[type] || '系统'
} }
function typeIcon(type: string) {
const map: Record<string, string> = {
order: 'orders-o',
handoff: 'logistics',
checkout: 'balance-list-o',
settlement: 'gold-coin-o',
dispute: 'warning-o',
arbitration: 'warning-o',
timeout: 'clock-o',
listing_review: 'certificate',
listing_admin: 'shop-o',
order_admin: 'service-o',
}
return map[type] || 'volume-o'
}
function typeTone(type: string) {
if (type === 'checkout' || type === 'settlement') return 'money'
if (type === 'dispute' || type === 'arbitration' || type === 'timeout') return 'warning'
if (type === 'listing_review' || type === 'listing_admin') return 'review'
if (type === 'order' || type === 'handoff' || type === 'order_admin') return 'order'
return 'system'
}
</script> </script>
<template> <template>
@@ -135,32 +159,42 @@ function typeLabel(type: string) {
class="notification-item" class="notification-item"
:class="{ unread: !item.read_at }" :class="{ unread: !item.read_at }"
> >
<div class="item-head"> <div class="item-type-icon" :class="`is-${typeTone(item.type)}`">
<span class="type-chip">{{ typeLabel(item.type) }}</span> <van-icon :name="typeIcon(item.type)" :size="20" />
<small>{{ formatDateMinute(item.created_at) }}</small>
</div> </div>
<h2>{{ item.title }}</h2> <div class="item-body">
<p>{{ item.content }}</p> <div class="item-meta">
<div class="item-actions"> <span class="type-chip">{{ typeLabel(item.type) }}</span>
<van-button <span v-if="!item.read_at" class="unread-label">未读</span>
v-if="item.biz_id && (item.biz_type === 'order' || item.biz_type === 'listing')" <time>{{ formatDateMinute(item.created_at) }}</time>
size="small" </div>
plain <h2>{{ item.title }}</h2>
round <p>{{ item.content }}</p>
type="primary" <div
@click="openBiz(item)" v-if="
!item.read_at ||
(item.biz_id && (item.biz_type === 'order' || item.biz_type === 'listing'))
"
class="item-actions"
> >
查看详情 <button
</van-button> v-if="item.biz_id && (item.biz_type === 'order' || item.biz_type === 'listing')"
<van-button type="button"
v-if="!item.read_at" class="detail-action"
size="small" @click.stop="openBiz(item)"
round >
type="primary" 查看详情
@click="markRead(item)" <van-icon name="arrow" :size="10" />
> </button>
已读 <button
</van-button> v-if="!item.read_at"
type="button"
class="read-action"
@click.stop="markRead(item)"
>
标为已读
</button>
</div>
</div> </div>
</article> </article>
@@ -186,17 +220,22 @@ function typeLabel(type: string) {
.mobile-notifications { .mobile-notifications {
min-height: 100dvh; min-height: 100dvh;
padding: 0 0 calc(64px + env(safe-area-inset-bottom)); padding: 0 0 calc(64px + env(safe-area-inset-bottom));
background: #f6f8fa; background: #f4f6f8;
color: #111827; color: #111827;
} }
.mobile-header { .mobile-header {
position: sticky;
top: 0;
z-index: 20;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 12px; gap: 12px;
padding: 16px; padding: 16px;
background: #fff; background: rgba(255, 255, 255, 0.94);
border-bottom: 1px solid #eef1f5; border-bottom: 1px solid #ffe9db;
backdrop-filter: blur(14px);
-webkit-backdrop-filter: blur(14px);
} }
.header-back { .header-back {
@@ -204,88 +243,202 @@ function typeLabel(type: string) {
width: 36px; width: 36px;
height: 36px; height: 36px;
place-items: center; place-items: center;
border: none; border: 1px solid #ffe2d1;
border-radius: 999px; border-radius: 999px;
background: #f3f4f6; background: #fff8f3;
color: #374151; color: #d94f00;
} }
.mobile-header h1 { .mobile-header h1 {
margin: 0; margin: 0;
font-size: 18px; font-size: 19px;
line-height: 24px; line-height: 25px;
font-weight: 900;
} }
.mobile-header p { .mobile-header p {
margin: 2px 0 0; margin: 3px 0 0;
color: #8a94a6; color: #8a94a6;
font-size: 12px; font-size: 11px;
line-height: 1.5;
} }
.notification-list { .notification-list {
display: grid; display: grid;
gap: 10px; gap: 10px;
padding: 12px; padding: 12px 14px 18px;
} }
.notification-item { .notification-item {
display: grid;
grid-template-columns: 40px minmax(0, 1fr);
gap: 12px;
padding: 14px; padding: 14px;
border: 1px solid #eef1f5; border: 1px solid #e8edf2;
border-radius: 8px; border-radius: 12px;
background: #fff; background: #fff;
box-shadow: 0 4px 14px rgba(15, 23, 42, 0.025);
} }
.notification-item.unread { .notification-item.unread {
border-color: rgba(255, 106, 0, 0.35); border-color: #ffd6bf;
background: #fffaf5; background: #fffdfb;
box-shadow:
inset 3px 0 #ff6a00,
0 4px 14px rgba(255, 106, 0, 0.045);
} }
.item-head { .item-type-icon {
display: grid;
width: 40px;
height: 40px;
align-items: center;
justify-items: center;
border-radius: 11px;
background: #fff1e8;
color: #ff6a00;
}
.item-type-icon.is-order {
background: #eff6ff;
color: #2563eb;
}
.item-type-icon.is-money {
background: #fff3e8;
color: #ea580c;
}
.item-type-icon.is-warning {
background: #fff7ed;
color: #d97706;
}
.item-type-icon.is-review {
background: #f5f3ff;
color: #7c3aed;
}
.item-type-icon.is-system {
background: #f1f5f9;
color: #64748b;
}
.item-body {
min-width: 0;
}
.item-meta {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; gap: 6px;
gap: 12px; min-width: 0;
} }
.type-chip { .type-chip {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
height: 22px; height: 20px;
padding: 0 8px; padding: 0 7px;
border-radius: 999px; border-radius: 999px;
background: #eef5ff; background: #fff1e8;
color: #2563eb; color: #d94f00;
font-size: 12px; font-size: 10px;
font-weight: 700; font-weight: 800;
} }
.item-head small { .unread-label {
display: inline-flex;
align-items: center;
gap: 4px;
color: #e65f00;
font-size: 10px;
font-weight: 800;
}
.unread-label::before {
width: 5px;
height: 5px;
border-radius: 999px;
background: #ff6a00;
content: '';
}
.item-meta time {
min-width: 0;
margin-left: auto;
overflow: hidden;
color: #9ca3af; color: #9ca3af;
font-size: 12px; font-size: 10px;
text-overflow: ellipsis;
white-space: nowrap;
} }
.notification-item h2 { .notification-item h2 {
margin: 10px 0 6px; margin: 8px 0 5px;
color: #111827; color: #111827;
font-size: 15px; font-size: 14px;
line-height: 22px; line-height: 20px;
font-weight: 800;
overflow-wrap: anywhere;
} }
.notification-item p { .notification-item p {
display: -webkit-box;
overflow: hidden;
margin: 0; margin: 0;
color: #4b5563; color: #5f6b7a;
font-size: 13px; font-size: 12px;
line-height: 20px; line-height: 19px;
overflow-wrap: anywhere;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
} }
.item-actions { .item-actions {
display: flex; display: flex;
justify-content: flex-end; align-items: center;
justify-content: space-between;
gap: 8px; gap: 8px;
margin-top: 12px; margin-top: 10px;
padding-top: 9px;
border-top: 1px solid #f1f3f6;
}
.detail-action,
.read-action {
display: inline-flex;
align-items: center;
gap: 3px;
min-height: 26px;
padding: 0;
border: 0;
background: transparent;
font-size: 11px;
font-weight: 800;
}
.detail-action {
color: #e65f00;
}
.read-action {
margin-left: auto;
padding: 0 10px;
border-radius: 999px;
background: #fff1e8;
color: #d94f00;
} }
.load-more { .load-more {
margin: 4px 0 12px; margin: 4px 0 12px;
} }
@media (min-width: 520px) {
.mobile-notifications {
max-width: 430px;
margin: 0 auto;
box-shadow: 0 0 0 1px rgba(23, 35, 61, 0.08);
}
}
</style> </style>
@@ -1,29 +1,40 @@
.mobile-profile-shell { .mobile-profile-shell {
min-height: 100dvh; min-height: 100dvh;
background: #f6f8fa; background: #f4f6f8;
color: #1a202c; color: #1a202c;
padding: 0 0 calc(64px + env(safe-area-inset-bottom)); padding: 0 0 calc(64px + env(safe-area-inset-bottom));
} }
/* ========== Hero Header ========== */ /* ========== Hero Header ========== */
.profile-hero { .profile-hero {
background: #ffffff; padding: 16px 16px 20px;
padding: 20px 16px 20px; border-bottom: 1px solid #fff1e8;
border-bottom: 1px solid rgba(243, 244, 246, 0.8); background: linear-gradient(180deg, #fff8f3 0%, #ffffff 82%);
} }
.hero-top-row { .hero-top-row {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 20px; margin-bottom: 14px;
}
.hero-title {
display: grid;
gap: 3px;
} }
.app-title { .app-title {
font-size: 16px; font-size: 17px;
font-weight: 700; font-weight: 900;
color: #111827; color: #111827;
letter-spacing: 0.5px; letter-spacing: 0;
}
.hero-title small {
color: #8b95a5;
font-size: 10px;
font-weight: 600;
} }
.hero-setting-btn { .hero-setting-btn {
@@ -31,8 +42,8 @@
width: 34px; width: 34px;
height: 34px; height: 34px;
place-items: center; place-items: center;
border: none; border: 1px solid rgba(255, 214, 191, 0.9);
background: #f3f4f6; background: rgba(255, 255, 255, 0.88);
border-radius: 999px; border-radius: 999px;
cursor: pointer; cursor: pointer;
transition: background 0.2s; transition: background 0.2s;
@@ -45,7 +56,7 @@
.profile-hero-content { .profile-hero-content {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 16px; gap: 12px;
} }
.avatar-circle { .avatar-circle {
@@ -55,11 +66,12 @@
place-items: center; place-items: center;
border-radius: 999px; border-radius: 999px;
overflow: hidden; overflow: hidden;
background: #eaf2ff; background: #fff1e8;
color: #1477ff; color: #ff6a00;
font-size: 24px; font-size: 24px;
font-weight: 900; font-weight: 900;
border: 1px solid #e5e7eb; border: 3px solid #fff;
box-shadow: 0 0 0 1px #ffd6bf;
} }
.avatar-circle img { .avatar-circle img {
@@ -76,13 +88,13 @@
.name-row { .name-row {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 6px;
flex-wrap: wrap; flex-wrap: wrap;
} }
.user-nickname { .user-nickname {
margin: 0; margin: 0;
font-size: 18px; font-size: 19px;
font-weight: 800; font-weight: 800;
color: #111827; color: #111827;
} }
@@ -107,58 +119,80 @@
} }
.user-meta { .user-meta {
margin: 4px 0 0; margin: 5px 0 0;
color: #6b7280; color: #7b8492;
font-size: 12px; font-size: 12px;
} }
.growth-card { .growth-card {
position: relative;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 10px; margin: 10px 16px 0;
margin: 12px 16px 0; overflow: hidden;
border: 1px solid #e9edf2;
border-radius: 14px;
background: #ffffff;
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.035);
} }
.growth-card > div { .growth-card > div {
display: grid; display: grid;
gap: 4px; gap: 4px;
min-width: 0; min-width: 0;
padding: 14px; padding: 12px 14px 10px;
border: 1px solid rgba(243, 244, 246, 0.9);
border-radius: 16px;
background: #ffffff;
box-shadow:
0 4px 16px rgba(0, 0, 0, 0.02),
0 1px 4px rgba(0, 0, 0, 0.02);
} }
.growth-card span { .growth-card > div + div {
border-left: 1px solid #f1f3f6;
}
.growth-card > div span {
color: #9ca3af; color: #9ca3af;
font-size: 11px; font-size: 10px;
font-weight: 700; font-weight: 700;
} }
.growth-card strong { .growth-card > div strong {
color: #7c3aed; color: #c2410c;
font-size: 20px; font-size: 18px;
line-height: 1.2; line-height: 1.2;
font-weight: 900; font-weight: 900;
} }
.growth-card.is-distribution > div { .growth-more {
background: #f0fdf4; grid-column: 1 / -1;
border-color: rgba(167, 243, 208, 0.6); display: flex;
align-items: center;
justify-content: space-between;
min-height: 30px;
padding: 7px 14px;
border: 0;
border-top: 1px solid #fff1e8;
background: #fffaf6;
color: #d94f00;
font-size: 10px;
font-weight: 800;
} }
.growth-card.is-distribution strong { .growth-card.is-distribution {
border-color: rgba(167, 243, 208, 0.7);
background: #f0fdf4;
}
.growth-card.is-distribution > div {
background: transparent;
}
.growth-card.is-distribution > div strong {
color: #059669; color: #059669;
} }
/* ========== Balance Card ========== */ /* ========== Balance Card ========== */
.balance-card { .balance-card {
margin: 12px 16px 14px; margin: 10px 16px 12px;
padding: 16px; padding: 14px;
border-radius: 16px; border-radius: 14px;
background: #ffffff; background: #ffffff;
box-shadow: box-shadow:
0 4px 16px rgba(0, 0, 0, 0.02), 0 4px 16px rgba(0, 0, 0, 0.02),
@@ -180,12 +214,12 @@
.balance-label { .balance-label {
color: #9ca3af; color: #9ca3af;
font-size: 11px; font-size: 10px;
font-weight: 600; font-weight: 600;
} }
.balance-value { .balance-value {
font-size: 26px; font-size: 24px;
font-weight: 800; font-weight: 800;
font-family: Inter, system-ui, sans-serif; font-family: Inter, system-ui, sans-serif;
color: #111827; color: #111827;
@@ -193,12 +227,12 @@
.withdraw-btn { .withdraw-btn {
background: transparent; background: transparent;
border: 1px solid #1477ff; border: 1px solid #ff6a00;
color: #1477ff; color: #ff6a00;
font-weight: 700; font-weight: 700;
font-size: 12px; font-size: 12px;
height: 28px; height: 26px;
padding: 0 16px; padding: 0 14px;
border-radius: 999px; border-radius: 999px;
cursor: pointer; cursor: pointer;
transition: transition:
@@ -207,22 +241,22 @@
} }
.withdraw-btn:active { .withdraw-btn:active {
background: #1477ff; background: #ff6a00;
color: #ffffff; color: #ffffff;
} }
.balance-footer { .balance-footer {
margin-top: 12px; margin-top: 9px;
padding-top: 10px; padding-top: 8px;
border-top: 1px solid #f3f4f6; border-top: 1px solid #f3f4f6;
} }
.detail-btn { .detail-btn {
background: transparent; background: transparent;
border: none; border: none;
color: #1477ff; color: #ff6a00;
font-weight: 700; font-weight: 700;
font-size: 11px; font-size: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
@@ -232,10 +266,10 @@
/* ========== Menu Cards ========== */ /* ========== Menu Cards ========== */
.menu-card { .menu-card {
margin: 0 16px 14px; margin: 10px 16px 12px;
background: #ffffff; background: #ffffff;
border-radius: 16px; border-radius: 14px;
padding: 16px; padding: 14px;
box-shadow: box-shadow:
0 4px 16px rgba(0, 0, 0, 0.02), 0 4px 16px rgba(0, 0, 0, 0.02),
0 1px 4px rgba(0, 0, 0, 0.02); 0 1px 4px rgba(0, 0, 0, 0.02);
@@ -247,16 +281,23 @@
overflow: hidden; overflow: hidden;
} }
.cell-card-title {
padding: 12px 16px 6px;
color: #697386;
font-size: 12px;
font-weight: 800;
}
.menu-card .card-header { .menu-card .card-header {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 14px; margin-bottom: 11px;
} }
.menu-card .card-header h3 { .menu-card .card-header h3 {
margin: 0; margin: 0;
font-size: 14px; font-size: 13px;
font-weight: 800; font-weight: 800;
color: #111827; color: #111827;
} }
@@ -293,7 +334,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 6px; gap: 4px;
cursor: pointer; cursor: pointer;
} }
@@ -303,8 +344,8 @@
.icon-wrap { .icon-wrap {
display: grid; display: grid;
width: 44px; width: 40px;
height: 44px; height: 40px;
place-items: center; place-items: center;
border-radius: 12px; border-radius: 12px;
transition: transform 0.15s ease; transition: transform 0.15s ease;
@@ -351,7 +392,7 @@
background: transparent; background: transparent;
} }
:deep(.van-cell) { :deep(.van-cell) {
padding: 14px 16px; padding: 12px 16px;
font-size: 14px; font-size: 14px;
} }
.verified-color { .verified-color {
@@ -676,12 +717,13 @@
.quality-owner-card { .quality-owner-card {
display: grid; display: grid;
gap: 12px; gap: 9px;
margin: 10px 12px; margin: 10px 16px 0;
padding: 16px; padding: 14px;
border: 1px solid #e9e2fb; border: 1px solid #e9e2fb;
border-radius: 14px; border-radius: 14px;
background: linear-gradient(135deg, #faf8ff 0%, #ffffff 72%); background: #ffffff;
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.035);
} }
.mobile-points-entry { .mobile-points-entry {
@@ -689,36 +731,72 @@
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: 12px; gap: 12px;
margin: 10px 12px; margin: 10px 16px 0;
padding: 14px 16px; padding: 11px 13px;
border: 1px solid #ffd6bf; border: 1px solid #ffd6bf;
border-radius: 14px; border-radius: 14px;
background: #fff8f3; background: linear-gradient(135deg, #fff8f3 0%, #ffffff 78%);
box-shadow: 0 4px 16px rgba(15, 23, 42, 0.035);
} }
.mobile-points-entry div { .points-entry-left {
display: flex;
align-items: center;
gap: 9px;
min-width: 0;
}
.points-entry-icon {
display: grid; display: grid;
gap: 3px; width: 36px;
height: 36px;
flex: 0 0 auto;
place-items: center;
border-radius: 11px;
background: #ffeadf;
} }
.mobile-points-entry span { .points-entry-copy {
color: #ff6a00; display: grid;
font-size: 10px; gap: 2px;
font-weight: 900;
} }
.mobile-points-entry strong { .points-entry-copy strong {
color: #c2410c; color: #c2410c;
font-size: 15px; font-size: 14px;
} }
.mobile-points-entry small { .points-entry-copy small {
color: #6b7280; color: #6b7280;
font-size: 10px; font-size: 9px;
} }
.quality-owner-card.is-active { .quality-owner-card.is-active {
border-color: #c4b5fd; border-color: #c4b5fd;
background: linear-gradient(145deg, #faf8ff 0%, #ffffff 66%);
}
.quality-owner-title {
display: flex;
align-items: center;
gap: 8px;
min-width: 0;
}
.quality-owner-icon {
display: grid;
width: 32px;
height: 32px;
flex: 0 0 auto;
place-items: center;
border-radius: 10px;
background: #f3e8ff;
color: #7c3aed !important;
}
.quality-owner-title > div {
display: grid;
gap: 1px;
} }
.quality-owner-heading, .quality-owner-heading,
@@ -729,7 +807,6 @@
gap: 10px; gap: 10px;
} }
.quality-owner-heading > div,
.quality-owner-info > div { .quality-owner-info > div {
display: grid; display: grid;
gap: 3px; gap: 3px;
@@ -744,24 +821,30 @@
.quality-owner-heading strong { .quality-owner-heading strong {
color: #312e81; color: #312e81;
font-size: 15px; font-size: 14px;
font-weight: 900; font-weight: 900;
} }
.quality-owner-info { .quality-owner-info {
gap: 8px; gap: 0;
overflow: hidden;
border: 1px solid #f0ebfb;
border-radius: 9px;
background: rgba(247, 245, 255, 0.9);
} }
.quality-owner-info > div { .quality-owner-info > div {
flex: 1; flex: 1;
padding: 10px; padding: 8px 10px;
border-radius: 8px; }
background: rgba(245, 243, 255, 0.85);
.quality-owner-info > div + div {
border-left: 1px solid #eee7fb;
} }
.quality-owner-info strong { .quality-owner-info strong {
color: #6d28d9; color: #6d28d9;
font-size: 14px; font-size: 13px;
font-weight: 900; font-weight: 900;
} }
@@ -770,13 +853,35 @@
gap: 8px; gap: 8px;
} }
.quality-owner-actions :deep(.van-button) {
height: 34px;
}
.quality-owner-footer {
display: flex;
align-items: center;
gap: 8px;
padding-top: 8px;
border-top: 1px solid #f0ecfb;
}
.quality-owner-card p { .quality-owner-card p {
flex: 1;
margin: 0; margin: 0;
color: #7b8492; color: #7b8492;
font-size: 11px; font-size: 10px;
line-height: 1.5; line-height: 1.5;
} }
.quality-owner-actions p {
text-align: center;
}
.quality-cancel-btn {
flex: 0 0 auto;
min-width: 72px;
}
/* ========== 响应式适配 ========== */ /* ========== 响应式适配 ========== */
@media (min-width: 520px) { @media (min-width: 520px) {
.mobile-profile-shell { .mobile-profile-shell {
@@ -454,10 +454,13 @@ function resolveAvatarURL(url: string | undefined | null) {
<main class="mobile-profile-shell"> <main class="mobile-profile-shell">
<!-- 已登录区 --> <!-- 已登录区 -->
<template v-if="isLoggedIn"> <template v-if="isLoggedIn">
<!-- Hero 顶部蓝色横幅 --> <!-- Hero 顶部账户概览 -->
<section class="profile-hero"> <section class="profile-hero">
<div class="hero-top-row"> <div class="hero-top-row">
<span class="app-title">个人中心</span> <div class="hero-title">
<span class="app-title">个人中心</span>
<small>账户、成长与权益管理</small>
</div>
<button class="hero-setting-btn" @click="showSettings = true"> <button class="hero-setting-btn" @click="showSettings = true">
<van-icon name="setting-o" :size="20" color="#374151" /> <van-icon name="setting-o" :size="20" color="#374151" />
</button> </button>
@@ -521,20 +524,29 @@ function resolveAvatarURL(url: string | undefined | null) {
</section> </section>
<section v-else class="growth-card"> <section v-else class="growth-card">
<div> <div>
<span>租客成长等级</span> <span>成长等级</span>
<strong>{{ session.renterGrowthLevelName }}</strong> <strong>{{ session.renterGrowthLevelName }}</strong>
</div> </div>
<div> <div>
<span>累计积分</span> <span>累计积分</span>
<strong>{{ session.renterGrowthPoints }}</strong> <strong>{{ session.renterGrowthPoints }}</strong>
</div> </div>
<button type="button" class="growth-more" @click="router.push('/m/benefits')">
<span>查看 VIP 与优质号主权益</span>
<van-icon name="arrow" :size="11" />
</button>
</section> </section>
<section class="quality-owner-card" :class="{ 'is-active': qualityOwnerStatus?.active }"> <section class="quality-owner-card" :class="{ 'is-active': qualityOwnerStatus?.active }">
<div class="quality-owner-heading"> <div class="quality-owner-heading">
<div> <div class="quality-owner-title">
<span>优质号主</span> <span class="quality-owner-icon">
<strong>{{ qualityOwnerStatus?.active ? '已开通' : '解锁极品专区发布权限' }}</strong> <van-icon name="award-o" :size="18" />
</span>
<div>
<span>优质号主</span>
<strong>{{ qualityOwnerStatus?.active ? '已开通' : '解锁极品专区发布权限' }}</strong>
</div>
</div> </div>
<van-tag :type="qualityOwnerStatus?.active ? 'success' : 'default'" round> <van-tag :type="qualityOwnerStatus?.active ? 'success' : 'default'" round>
{{ qualityOwnerStatus?.active ? '优质号主' : '未开通' }} {{ qualityOwnerStatus?.active ? '优质号主' : '未开通' }}
@@ -546,7 +558,7 @@ function resolveAvatarURL(url: string | undefined | null) {
<strong>¥{{ formatCent(qualityOwnerStatus?.required_deposit_cent || 20000) }}</strong> <strong>¥{{ formatCent(qualityOwnerStatus?.required_deposit_cent || 20000) }}</strong>
</div> </div>
<div> <div>
<span>极品专区保险费率</span> <span>极品专区保险</span>
<strong <strong
>{{ >{{
((qualityOwnerStatus?.premium_insurance_fee_bps || 400) / 100).toFixed(1) ((qualityOwnerStatus?.premium_insurance_fee_bps || 400) / 100).toFixed(1)
@@ -554,17 +566,28 @@ function resolveAvatarURL(url: string | undefined | null) {
> >
</div> </div>
</div> </div>
<div v-if="qualityOwnerStatus?.active" class="quality-owner-actions"> <div v-if="qualityOwnerStatus?.active" class="quality-owner-footer">
<p>
<template v-if="qualityOwnerStatus.active_premium_listing_count > 0">
极品专区还有 {{ qualityOwnerStatus.active_premium_listing_count }}
个进行中账号,需处理后可取消。
</template>
<template v-else-if="qualityOwnerStatus.deposit_source === 'manual'">
已由后台开通优质号主,可随时取消。
</template>
<template v-else>保证金已冻结,取消后退回可用余额。</template>
</p>
<van-button <van-button
block size="small"
round round
plain plain
type="danger" type="danger"
class="quality-cancel-btn"
:loading="qualityOwnerCancelling" :loading="qualityOwnerCancelling"
:disabled="qualityOwnerStatus.active_premium_listing_count > 0" :disabled="qualityOwnerStatus.active_premium_listing_count > 0"
@click="handleCancelQualityOwner" @click="handleCancelQualityOwner"
> >
取消优质号主 取消资格
</van-button> </van-button>
</div> </div>
<div v-else class="quality-owner-actions"> <div v-else class="quality-owner-actions">
@@ -592,24 +615,19 @@ function resolveAvatarURL(url: string | undefined | null) {
> >
微信 / 支付宝支付开通 微信 / 支付宝支付开通
</van-button> </van-button>
<p>开通后可发布到极品专区,并享受该专区专享保险费率。</p>
</div> </div>
<p v-if="qualityOwnerStatus?.active">
<template v-if="qualityOwnerStatus.active_premium_listing_count > 0">
极品专区还有 {{ qualityOwnerStatus.active_premium_listing_count }}
个进行中账号,请先下架或完成订单后再取消。
</template>
<template v-else-if="qualityOwnerStatus.deposit_source === 'manual'">
已由后台开通优质号主,可随时取消。
</template>
<template v-else> 保证金已冻结,取消后可退回可用余额。 </template>
</p>
</section> </section>
<section class="mobile-points-entry" @click="router.push('/m/points-mall')"> <section class="mobile-points-entry" @click="router.push('/m/points-mall')">
<div> <div class="points-entry-left">
<span>积分商城</span> <span class="points-entry-icon">
<strong>{{ session.pointsAvailable }} 可用积分</strong> <van-icon name="point-gift-o" :size="22" color="#ff6a00" />
<small>{{ session.renterGrowthLevelName }}等级</small> </span>
<div class="points-entry-copy">
<strong>{{ session.pointsAvailable }} 可用积分</strong>
<small>积分商城 · {{ session.renterGrowthLevelName }}等级</small>
</div>
</div> </div>
<van-icon name="arrow" /> <van-icon name="arrow" />
</section> </section>
@@ -618,7 +636,7 @@ function resolveAvatarURL(url: string | undefined | null) {
<div class="balance-card"> <div class="balance-card">
<div class="balance-row"> <div class="balance-row">
<div class="balance-info"> <div class="balance-info">
<span class="balance-label">账户可用余额(元)</span> <span class="balance-label">账户可用余额</span>
<strong class="balance-value">¥{{ formatCent(availableBalanceCent) }}</strong> <strong class="balance-value">¥{{ formatCent(availableBalanceCent) }}</strong>
</div> </div>
<button class="withdraw-btn" @click="handleWithdraw">提现</button> <button class="withdraw-btn" @click="handleWithdraw">提现</button>
@@ -683,8 +701,9 @@ function resolveAvatarURL(url: string | undefined | null) {
</div> </div>
</div> </div>
<!-- 常用功能 Cell Group --> <!-- 消息与公告 -->
<div class="menu-card cell-card"> <div class="menu-card cell-card">
<div class="cell-card-title">消息与公告</div>
<van-cell-group :border="false"> <van-cell-group :border="false">
<van-cell title="消息中心" icon="chat-o" is-link to="/m/messages" /> <van-cell title="消息中心" icon="chat-o" is-link to="/m/messages" />
<van-cell title="站内信" icon="envelop-o" is-link to="/m/notifications"> <van-cell title="站内信" icon="envelop-o" is-link to="/m/notifications">
@@ -695,6 +714,13 @@ function resolveAvatarURL(url: string | undefined | null) {
</template> </template>
</van-cell> </van-cell>
<van-cell title="公告中心" icon="volume-o" is-link to="/m/announcements" /> <van-cell title="公告中心" icon="volume-o" is-link to="/m/announcements" />
</van-cell-group>
</div>
<!-- 账户与常用服务 -->
<div class="menu-card cell-card">
<div class="cell-card-title">账户与服务</div>
<van-cell-group :border="false">
<van-cell title="资料修改" icon="edit" is-link @click="openProfileEditor" /> <van-cell title="资料修改" icon="edit" is-link @click="openProfileEditor" />
<van-cell title="修改密码" icon="lock" is-link @click="openPasswordEditor" /> <van-cell title="修改密码" icon="lock" is-link @click="openPasswordEditor" />
<van-cell title="实名认证" icon="idcard" is-link to="/m/realname"> <van-cell title="实名认证" icon="idcard" is-link to="/m/realname">
@@ -711,6 +737,7 @@ function resolveAvatarURL(url: string | undefined | null) {
to="/m/invitations" to="/m/invitations"
:value="inviteRateText || '阶梯返利'" :value="inviteRateText || '阶梯返利'"
/> />
<van-cell title="权益中心" icon="medal-o" is-link to="/m/benefits" />
<van-cell title="租后须知" icon="info-o" is-link @click="openPostRentalNotice" /> <van-cell title="租后须知" icon="info-o" is-link @click="openPostRentalNotice" />
<van-cell title="系统设置" icon="setting-o" is-link @click="showSettings = true" /> <van-cell title="系统设置" icon="setting-o" is-link @click="showSettings = true" />
</van-cell-group> </van-cell-group>