feat(BD中心): 新UI

This commit is contained in:
hzj 2025-10-28 12:06:33 +08:00
parent 0ba55b0013
commit 304e3e8c55

View File

@ -4,92 +4,379 @@
<MobileHeader title="BD Center" :isHomePage="true" />
<!-- 主要内容 -->
<div class="content">
<div
style="
padding: 16px;
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
gap: 12px;
"
>
<!-- 用户信息卡片 -->
<div class="user-card">
<div
style="
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
"
>
<!-- APP连接状态指示 -->
<div v-if="isInApp() && !appConnected" class="app-status connecting">
<div class="status-indicator"></div>
<span>正在连接APP...</span>
</div>
<div class="user-info">
<div class="avatar">
<div style="display: flex; align-items: center">
<div
style="
width: 50px;
height: 50px;
border-radius: 25px;
background-color: #8b5cf6;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: 600;
margin-right: 12px;
overflow: hidden;
position: relative;
"
>
<img
v-if="userInfo.userAvatar"
style="width: 100%; height: 100%; object-fit: cover; border-radius: 25px"
:src="userInfo.userAvatar"
:alt="userInfo.name"
@error="handleImageError"
/>
<span v-else class="avatar-placeholder">{{ getAvatarPlaceholder() }}</span>
<span v-else style="color: white; font-size: 20px; font-weight: 600">{{
getAvatarPlaceholder()
}}</span>
</div>
<div class="user-details">
<h3>{{ userInfo.userNickname || userInfo.name }}</h3>
<p>ID: {{ userInfo.id || userInfo.account }}</p>
<div style="flex: 1">
<h3 style="margin: 0 0 4px 0; font-weight: 600; color: #333">
{{ userInfo.userNickname || userInfo.name }}
</h3>
<p style="margin: 0; font-size: 0.9em; color: #666">
ID: {{ userInfo.id || userInfo.account }}
</p>
</div>
<!-- <button class="notification-btn" @click="goToNotification">-->
<!-- <span></span>-->
<!-- </button>-->
</div>
<!-- 账户状态标签 -->
<div class="account-tags">
<img src="../assets/icon/BD.png" alt="" height="20px" style="margin-left: 10px" />
</div>
</div>
<!-- Total team salary 区域 -->
<div class="salary-section">
<h3>Total team salary:</h3>
<div class="salary-content">
<div class="salary-item">
<p class="salary-label">Last month:</p>
<p class="salary-amount">${{ salaryInfo.lastMonth }}</p>
</div>
<div class="salary-separator"></div>
<div class="salary-item">
<p class="salary-label">This month:</p>
<p class="salary-amount">${{ salaryInfo.thisMonth }}</p>
<div style="display: flex; align-items: center">
<img src="../assets/icon/info.png" alt="" style="display: block; width: 20px" />
</div>
</div>
</div>
<!-- Team Member 卡片 -->
<div class="team-member-section">
<div class="team-member-card" @click="goToTeamMember">
<div class="card-content">
<span class="member-title">
Team Member
<span v-if="loadingMemberCount">(Loading...)</span>
<span v-else>({{ teamMemberCount }})</span>
</span>
<span class="arrow">></span>
</div>
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
"
>
<span style="font-weight: 600; color: #1f2937"> Available income:$0 </span>
<img src="../assets/icon/arrow.png" alt="" style="display: block; width: 20px" />
</div>
</div>
<!-- 邀请代理 -->
<div class="team-member-section">
<div class="team-member-card" @click="goToInviteAgency">
<div class="card-content">
<span class="member-title"> Invite user to become agency </span>
<span class="arrow">></span>
</div>
<div
style="
background-color: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 16px;
cursor: pointer;
transition: all 0.2s;
border: 1px solid #e5e7eb;
display: flex;
flex-direction: column;
gap: 10px;
"
@click="goToInviteAgency"
>
<div style="display: flex; justify-content: space-between; align-items: center">
<span style="font-weight: 600; color: #1f2937"> Invite User To Become Agency</span>
<img src="../assets/icon/arrow.png" alt="" style="display: block; width: 20px" />
</div>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<button class="action-btn exchange-btn" @click="exchangeGoldCoins">Exchange</button>
<button class="action-btn transfer-btn" @click="transfer">Transfer</button>
<!-- 收入 -->
<div
style="
background-color: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
padding: 16px;
cursor: pointer;
transition: all 0.2s;
border: 1px solid #e5e7eb;
display: flex;
flex-direction: column;
gap: 10px;
"
>
<div style="font-weight: 700">BD</div>
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="font-weight: 600">2025.10.01-2025.10.15:</div>
<img
src="../assets/icon/records.png"
alt=""
style="display: block; width: 1.3em"
@click="showHistory = true"
/>
</div>
<div style="font-size: 0.7em; font-weight: 600">
Team total recharge: $400 Team total salary: $400
</div>
<div
v-for="value in 3"
style="
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
"
>
<!-- 用户信息 -->
<div
style="
position: relative;
width: 2em;
display: flex;
align-items: center;
justify-content: center;
"
>
<img
:src="''"
alt=""
style="
display: block;
width: 100%;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="defaultAvatarUrl"
/>
</div>
<div style="width: calc(60% - 62px); display: flex; flex-direction: column; gap: 4px">
<div
style="
font-weight: 700;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
aaaaa
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-size: 0.8em; font-weight: 500">
ID: 321654
</div>
</div>
<div
style="width: 40%; display: flex; flex-direction: column; justify-content: space-around"
>
<div style="font-size: 0.8em; font-weight: 500">Salary: $100</div>
<div style="font-size: 0.8em; font-weight: 500">Recharge: $500</div>
<div style="font-size: 0.8em; font-weight: 500">Host:8</div>
</div>
</div>
</div>
</div>
<!-- 遮罩层 -->
<maskLayer :maskLayerShow="maskLayerShow" @click="closedPopup">
<div style="position: fixed; bottom: 0; width: 100%">
<!-- 历史收入 -->
<div
v-if="showHistory"
style="
background: white;
border-radius: 16px 16px 0 0;
max-height: 80vh;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 10px;
padding: 20px;
"
@click.stop
>
<div style="display: flex; justify-content: center; align-items: center">
<div style="margin: 0; font-size: 18px; font-weight: 600; color: #333">BD Salary</div>
</div>
<!-- 等级卡片 -->
<div
style="
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
border-radius: 8px;
padding: 12px;
margin: 0 4px;
"
>
<div>
<div style="display: grid; gap: 10px">
<div class="text-700">Total income:$1000</div>
<div class="text-700">Previous period income:$1000</div>
</div>
</div>
</div>
<div style="overflow-y: auto" class="salaryList">
<!-- 薪资列表 -->
<div style="display: flex; flex-direction: column; gap: 8px">
<!-- <historySalary type="In Progress">
<template v-slot:content>
<div>2025.10.16-2025.10.31:</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr)">
<div>Number of BDs: 5</div>
<div>Team Salary: $400</div>
</div>
</template>
</historySalary> -->
<historySalary type="In Progress" long="true">
<template v-slot:content>
<div>2025.10.16-2025.10.31:</div>
<div>Number of teams: 5</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr)">
<div>Team salary: $400</div>
<div>BD income (salary): $12 (3%)</div>
</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr)">
<div>Team salary: $400</div>
<div>BD income (salary): $12 (3%)</div>
</div>
</template>
</historySalary>
<historySalary type="Completed" v-for="value in 5" @showMore="showReportDetail()">
<template v-slot:content>
<div>2025.10.16-2025.10.31:</div>
<div>Number Of Teams: 5</div>
<div style="display: grid; grid-template-columns: repeat(2, 1fr)">
<div>Number Of Teams: 5</div>
<div>BD income (salary): $60 (6%)</div>
</div>
</template>
</historySalary>
</div>
</div>
</div>
<!-- 收入详情 -->
<div
v-if="showMore"
style="
background: white;
border-radius: 16px 16px 0 0;
max-height: 60vh;
overflow: hidden;
display: flex;
flex-direction: column;
gap: 10px;
padding: 20px;
"
@click.stop
>
<div style="font-weight: 600">2025.10.01-2025.10.15:</div>
<div style="font-size: 0.7em; font-weight: 600">
Team total recharge: $400 Team total salary: $400
</div>
<div
v-for="value in 3"
style="
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
"
>
<!-- 用户信息 -->
<div
style="
position: relative;
width: 2em;
display: flex;
align-items: center;
justify-content: center;
"
>
<img
:src="''"
alt=""
style="
display: block;
width: 100%;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="defaultAvatarUrl"
/>
</div>
<div style="width: calc(60% - 62px); display: flex; flex-direction: column; gap: 4px">
<div
style="
font-weight: 700;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
aaaaa
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-size: 0.8em; font-weight: 500">
ID: 321654
</div>
</div>
<div
style="
width: 40%;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div style="font-size: 0.8em; font-weight: 500">Salary: $100</div>
<div style="font-size: 0.8em; font-weight: 500">Recharge: $500</div>
<div style="font-size: 0.8em; font-weight: 500">Host:8</div>
</div>
</div>
</div>
</div>
</maskLayer>
</div>
</template>
<script setup>
import { onMounted, ref } from 'vue'
import { computed, onMounted, ref } from 'vue'
import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue'
import { getAgentMonthLastTarget, getAgentMonthTarget, getBdAgentList } from '../api/teamBill.js'
@ -97,26 +384,38 @@ import { getTeamId } from '@/utils/userStore.js'
import { usePageInitializationWithConfig } from '@/utils/pageConfig.js'
import { isInApp } from '@/utils/appBridge.js'
import { clearSelectedPayee } from '../utils/payeeStore.js'
import maskLayer from '@/components/MaskLayer.vue'
import historySalary from '@/components/historySalary.vue'
const router = useRouter()
//
const teamMemberCount = ref(0)
const loadingMemberCount = ref(false)
const showHistory = ref(false) //
const showMore = ref(false) //
const getAgentMonth = async () => {
const res = await getAgentMonthTarget()
if (res.status === true) {
salaryInfo.thisMonth = res.body.thisMonthTotalTarget
teamMemberCount.value = res.body.agentQuantity
}
const res2 = await getAgentMonthLastTarget()
if (res2.status === true) {
salaryInfo.lastMonth = res2.body.thisMonthTotalTarget
}
const defaultAvatarUrl = (e) => {
console.log('头像资源出错')
e.target.onerror = null //
e.target.src = new URL('/src/assets/images/WeeklyStar/defaultAvatar.png', import.meta.url).href
}
const maskLayerShow = computed(() => {
return showHistory.value || showMore.value
})
const showReportDetail = () => {
showHistory.value = false
showMore.value = true
}
//
const closedPopup = () => {
showHistory.value = false
showMore.value = false
}
//
const goToTeamMember = () => {
router.push({
path: '/team-member',
@ -124,14 +423,17 @@ const goToTeamMember = () => {
})
}
//
const goToInviteAgency = () => {
router.push('/invite-agency')
}
//
const exchangeGoldCoins = () => {
router.push('/exchange-gold-coins')
}
//
const transfer = () => {
router.push('/transfer')
}
@ -139,9 +441,7 @@ const transfer = () => {
const { appConnected, userInfo, salaryInfo, handleImageError, getAvatarPlaceholder } =
usePageInitializationWithConfig('BD_CENTER', {
needsTeamInfo: true,
onDataLoaded: () => {
getAgentMonth()
},
onDataLoaded: () => {},
})
onMounted(() => {
@ -150,25 +450,15 @@ onMounted(() => {
</script>
<style scoped>
* {
color: rgba(0, 0, 0, 0.8);
font-family: 'SF Pro Text';
}
.bd-center {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}
.content {
padding: 16px;
position: relative;
z-index: 2;
}
/* 用户信息卡片 */
.user-card {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
/* APP连接状态 */
.app-status {
display: flex;
@ -186,11 +476,6 @@ onMounted(() => {
color: #d97706;
}
.app-status.connected {
background-color: #d1fae5;
color: #059669;
}
.status-indicator {
width: 8px;
height: 8px;
@ -202,6 +487,10 @@ onMounted(() => {
animation: pulse 1.5s ease-in-out infinite;
}
.salaryList::-webkit-scrollbar {
display: none;
}
@keyframes pulse {
0%,
100% {
@ -212,205 +501,27 @@ onMounted(() => {
}
}
.user-info {
display: flex;
align-items: center;
margin-bottom: 12px;
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
.avatar {
width: 50px;
height: 50px;
border-radius: 25px;
background-color: #8b5cf6;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
font-weight: 600;
margin-right: 12px;
overflow: hidden;
position: relative;
@media screen and (min-width: 360px) {
* {
font-size: 16px;
}
}
.avatar img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 25px;
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
.avatar .avatar-placeholder {
color: white;
font-size: 20px;
font-weight: 600;
}
.user-details {
flex: 1;
}
.user-details h3 {
margin: 0 0 4px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.user-details p {
margin: 0;
font-size: 14px;
color: #666;
}
.system-info {
font-size: 12px !important;
color: #8b5cf6 !important;
margin-top: 2px !important;
}
.notification-btn {
width: 32px;
height: 32px;
border: none;
background: none;
font-size: 16px;
cursor: pointer;
}
.account-tags {
display: flex;
gap: 8px;
}
.tag {
padding: 4px 12px;
border-radius: 16px;
font-size: 12px;
font-weight: 600;
}
.bd-tag {
background-color: #e0e7ff;
color: #5b21b6;
}
/* Total team salary 区域 */
.salary-section {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.salary-section h3 {
margin: 0 0 16px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.salary-content {
display: flex;
align-items: center;
gap: 20px;
}
.salary-item {
flex: 1;
text-align: center;
}
.salary-label {
margin: 0 0 8px 0;
font-size: 14px;
color: #666;
}
.salary-amount {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #333;
}
.salary-separator {
width: 1px;
height: 40px;
background-color: #8b5cf6;
}
/* Team Member 独立区域 */
.team-member-section {
margin-bottom: 16px;
}
.team-member-card {
background-color: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
cursor: pointer;
transition: all 0.2s;
border: 1px solid #e5e7eb;
}
.team-member-card:active {
transform: scale(0.98);
}
.team-member-card .card-content {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
}
.member-title {
font-size: 16px;
font-weight: 600;
color: #1f2937;
}
/* 操作按钮 */
.action-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.action-btn {
padding: 14px 12px;
border: none;
border-radius: 12px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
text-align: center;
line-height: 1.2;
transition: all 0.2s;
width: 100%;
}
.action-btn:active {
transform: scale(0.98);
}
.exchange-btn {
background-color: #fde68a;
color: #d97706;
}
.transfer-btn {
background-color: #8b5cf6;
color: white;
}
/* 通用箭头样式 */
.arrow {
font-size: 16px;
font-weight: bold;
color: #8b5cf6;
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
</style>