771 lines
21 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="bd-center gradient-background-circles">
<!-- 顶部导航 -->
<GeneralHeader
:isHomePage="true"
:showLanguageList="true"
:title="t('bd_center')"
color="black"
style="box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); z-index: 999"
/>
<!-- 主要内容 -->
<div
style="
padding: 16px;
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
gap: 12px;
"
>
<!-- 用户信息卡片 -->
<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>{{ t('loading') }}...</span>
</div>
<!-- 用户信息 -->
<div style="display: flex; align-items: center; gap: 4px">
<!-- 头像 -->
<div style="width: 3.5em; display: flex; align-items: center; justify-content: center">
<img
:src="userInfo.userAvatar || ''"
style="
display: block;
width: 100%;
aspect-ratio: 1/1;
object-fit: cover;
border-radius: 50%;
"
@error="handleAvatarImageError"
/>
</div>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div
style="
margin-bottom: 4px;
font-weight: 600;
color: #333;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
"
>
{{ userInfo.userNickname || userInfo.name }}
</div>
<div style="margin: 0; font-size: 0.9em; color: #666">
ID: {{ userInfo.id || userInfo.account }}
</div>
</div>
<!-- 按钮 -->
<div style="display: flex; align-items: center" @click="gotoPolicy">
<img src="../../assets/icon/info.png" alt="" style="display: block; width: 20px" />
</div>
</div>
<!-- 前往收入页面 -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 10px;
"
@click="gotoIncome"
>
<span style="font-weight: 600; color: #1f2937">
{{ t('available_salaries') }} ${{ salaryInfo?.availableBalance || 0 }}
</span>
<img
src="../../assets/icon/arrow.png"
alt=""
style="display: block; width: 20px"
class="flipImg"
/>
</div>
</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"> {{ t('invite_become_agent') }}</span>
<img
src="../../assets/icon/arrow.png"
alt=""
style="display: block; width: 20px"
class="flipImg"
/>
</div>
</div>
<!-- BD团队列表 & 收入 -->
<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">{{ t('bd') }}</div>
<!-- 日期 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<div style="font-weight: 600">{{ BDData.billTitle }}</div>
<img
src="../../assets/icon/records.png"
alt=""
style="display: block; width: 1.3em"
@click="showHistory = true"
/>
</div>
<!-- 总体信息 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<!-- 总支出 -->
<div style="font-size: 0.8em; font-weight: 600">
{{ t('team_recharge') }}: ${{ BDData.totalRecharge }}
</div>
<!-- 总收入 -->
<div style="font-size: 0.8em; font-weight: 600">
{{ t('total_team_salary') }}: ${{ BDData.totalSalary }}
</div>
</div>
<!-- 成员列表 -->
<div
v-for="BDInfo in BDData.memberBillList"
style="
background-color: white;
padding: 10px 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-between;
gap: 4px;
"
>
<!-- 头像 -->
<div
style="
width: 3.5em;
display: flex;
align-items: center;
justify-content: center;
"
>
<img
:src="BDInfo.agentAvatar || ''"
alt=""
style="
display: block;
width: 100%;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
</div>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
gap: 4px;
"
>
<div
style="
font-weight: 700;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ BDInfo.agentName }}
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-size: 0.8em; font-weight: 500">
ID: {{ BDInfo.agentAccount }}
</div>
</div>
<div
style="
width: auto;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('salary') }}: ${{ BDInfo.teamSalaryAmount }}
</div>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('recharge') }}: ${{ BDInfo.teamRechargeAmount }}
</div>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('host') }}:{{ BDInfo.teamMemberCount }}
</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;
display: flex;
flex-direction: column;
gap: 10px;
padding: 20px;
"
class="overflow-y-auto"
@click.stop
>
<!-- 标题 -->
<div style="display: flex; justify-content: center; align-items: center">
<div style="margin: 0; font-size: 18px; font-weight: 600; color: #333">
{{ t('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: 4px">
<div style="font-size: 0.9em; font-weight: 600">
{{ t('total_income') }}: ${{ BDSalary.totalIncome }}
</div>
<div style="font-size: 0.9em; font-weight: 600">
{{ t('previous_period_income') }}: ${{ BDSalary.previousPeriodIncome }}
</div>
</div>
</div>
</div>
<div style="overflow-y: auto" class="salaryList">
<!-- 薪资列表 -->
<div style="display: flex; flex-direction: column; gap: 8px">
<historySalary
v-for="income in BDSalary.incomeDetails"
:type="income.statusText"
long="true"
@showMore="showReportDetail(income.billBelong)"
>
<!-- 进行中 -->
<template v-if="income.statusText == 'In Progress'" v-slot:content>
<div>{{ income.billTitle }}</div>
<div style="font-size: 0.9em">
{{ t('agency_number') }}: {{ income.agencyNumber || 0 }}
</div>
<!-- 团队薪资和BD薪资收益 -->
<div style="display: flex; justify-content: space-between">
<div style="font-size: 0.9em">
{{ t('team_salary') }}: ${{ income.teamSalaryAmount || 0 }}
</div>
<div style="font-size: 0.9em">
{{ t('bd_income_salary') }}: ${{ income.bdIncomeSalary || 0 }} ({{
income.bdRatioSalary || 0
}}%)
</div>
</div>
<!-- 团队充值和BD充值收益 -->
<div style="display: flex; justify-content: space-between">
<div style="font-size: 0.9em">
{{ t('team_top_up') }}: ${{ income.teamRechargeAmount || 0 }}
</div>
<div style="font-size: 0.9em">
{{ t('bd_income_top_up') }}: ${{ income.bdIncomeRecharge || 0 }} ({{
income.bdRatioRecharge || 0
}}%)
</div>
</div>
</template>
<!-- 已完成 -->
<template v-else v-slot:content>
<div>{{ income.billTitle }}</div>
<div style="font-size: 0.9em">
{{ t('num_teams') }}: {{ income.agencyNumber || 0 }}
</div>
<!-- 展示团队薪资高收入 -->
<div
v-if="income.hitPolicyType == 'TEAM_SALARY'"
style="display: flex; justify-content: space-between"
>
<!-- 团队薪资 -->
<div style="font-size: 0.9em">
{{ t('team_salary') }}: ${{ income.teamSalaryAmount || 0 }}
</div>
<!-- 薪资收益 -->
<div style="font-size: 0.9em">
{{ t('bd_income_salary') }}: ${{ income.settlementSalary || 0 }} ({{
income.commissionRate || 0
}}%)
</div>
</div>
<!-- 展示团队充值高支出 -->
<div
v-else-if="income.hitPolicyType == 'TEAM_RECHARGE'"
style="display: flex; justify-content: space-between"
>
<!-- 团队充值 -->
<div style="font-size: 0.9em">
{{ t('team_top_up') }}: ${{ income.teamRechargeAmount || 0 }}
</div>
<!-- 充值收益 -->
<div style="font-size: 0.9em">
{{ t('bd_income_top_up') }}: ${{ income.settlementSalary || 0 }} ({{
income.commissionRate || 0
}}%)
</div>
</div>
</template>
</historySalary>
</div>
</div>
</div>
<!-- 收入详情 -->
<div
v-if="showMore"
style="
background: white;
border-radius: 16px 16px 0 0;
max-height: 60vh;
display: flex;
flex-direction: column;
gap: 10px;
padding: 20px;
"
class="overflow-y-auto"
@click.stop
>
<!-- 日期 -->
<div style="font-weight: 600">{{ BDSalaryMore.period }}</div>
<!-- 总体信息 -->
<div style="display: flex; justify-content: space-between; align-items: center">
<!-- 总支出 -->
<div style="font-size: 0.7em; font-weight: 600">
{{ t('team_recharge') }}: ${{ BDSalaryMore.teamTotalRecharge }}
</div>
<!-- 总收入 -->
<div style="font-size: 0.7em; font-weight: 600">
{{ t('total_team_salary') }}: ${{ BDSalaryMore.teamTotalSalary }}
</div>
</div>
<!-- 代理列表 -->
<div
v-for="member in BDSalaryMore.memberDetails"
style="
background-color: white;
padding: 10px 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: space-around;
gap: 4px;
"
>
<!-- 头像 -->
<div
style="
width: 3.5em;
display: flex;
align-items: center;
justify-content: center;
"
>
<img
:src="member.userAvatar || ''"
alt=""
style="
display: block;
width: 100%;
aspect-ratio: 1/1;
border-radius: 50%;
object-fit: cover;
"
@error="handleAvatarImageError"
/>
</div>
<!-- 基本信息 -->
<div
style="
flex: 1;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
gap: 4px;
"
>
<div
style="
font-weight: 700;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
"
>
{{ member.userName }}
</div>
<div style="color: rgba(0, 0, 0, 0.4); font-size: 0.8em; font-weight: 500">
ID: {{ member.account }}
</div>
</div>
<!-- 关键信息 -->
<div
style="
width: auto;
min-width: 0;
align-self: stretch;
display: flex;
flex-direction: column;
justify-content: space-around;
"
>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('salary') }}: ${{ member.salary }}
</div>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('recharge') }}: ${{ member.recharge }}
</div>
<div style="font-size: 0.8em; font-weight: 500">
{{ t('host') }}:{{ member.hostCount }}
</div>
</div>
</div>
</div>
</div>
</maskLayer>
</div>
</template>
<script setup>
import { computed, onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router'
import { usePageInitializationWithConfig } from '@/utils/pageConfig.js'
import { isInApp } from '@/utils/appBridge.js'
import { clearSelectedPayee } from '@/utils/payeeStore.js'
import { setDocumentDirection } from '@/locales/i18n'
import { useIdentityStore } from '@/stores/identity.js'
import { handleAvatarImageError } from '@/utils/imageHandler.js'
import { getBdMemberBillList, getBdHistory, getBdHistoryMore } from '@/api/bdCenter.js'
import { apiGetBankBalance } from '@/api/wallet.js'
import GeneralHeader from '@/components/GeneralHeader.vue'
import maskLayer from '@/components/MaskLayer.vue'
import historySalary from '@/components/historySalary.vue'
const { t, locale } = useI18n()
const router = useRouter()
const identityStore = useIdentityStore()
// 监听语言变化并设置文档方向
locale.value && setDocumentDirection(locale.value)
// 当前身份
const showHistory = ref(false) //历史弹窗
const showMore = ref(false) //更多弹窗
const BDSalary = ref({}) //BD历史收入
const BDSalaryMore = ref({}) //BD历史收入更多
const BDData = ref({}) //BD成员数据
const salaryInfo = ref({}) //钱包信息
const maskLayerShow = computed(() => {
return showHistory.value || showMore.value
})
// 关闭弹窗
const closedPopup = () => {
showHistory.value = false
showMore.value = false
}
// 前往政策页
const gotoPolicy = () => {
router.push({
path: '/policy',
query: { from: 'BD' },
})
}
const gotoIncome = () => {
router.push('/available-income')
}
// 前往邀请代理
const goToInviteAgency = () => {
router.push('/invite-agency')
}
// 查询可用余额
const getBankBalance = async () => {
const res = await apiGetBankBalance('BD_SALARY')
if (res.status && res.body) {
salaryInfo.value = res.body || {}
}
}
const { appConnected, userInfo } = usePageInitializationWithConfig('BD_CENTER', {
forceRefresh: true, // 强制刷新
needsTeamInfo: true,
needsBankBalance: false,
onDataLoaded: () => {},
})
// 查询BD成员账单列表
const apiGetBdMemberBillList = async () => {
const res = await getBdMemberBillList('BD')
if (res.status && res.body) {
BDData.value = res.body || {}
// 如果BDSalary.value获取完数据就整合数据
if (BDSalary.value.incomeDetails) {
BDSalary.value.incomeDetails.unshift(BDData.value.bdHistoryCO)
}
}
}
// 查询BD历史记录
const apiGetBdHistory = async () => {
const res = await getBdHistory()
if (res.status && res.body) {
BDSalary.value = res.body || {}
// 如果BDData.value获取完数据就整合数据
if (BDData.value.bdHistoryCO) {
BDSalary.value.incomeDetails.unshift(BDData.value.bdHistoryCO)
}
}
}
// 查询BD历史记录
const showReportDetail = async (billBelong) => {
const res = await getBdHistoryMore(billBelong)
if (res.status && res.body) {
BDSalaryMore.value = res.body || {}
showHistory.value = false
showMore.value = true
}
}
// 页面初始化数据
const initData = async () => {
apiGetBdMemberBillList() //BD成员账单列表
apiGetBdHistory() //BD历史记录
getBankBalance() // 查询可用余额
}
onMounted(() => {
clearSelectedPayee() //清除选中的收款人
initData()
identityStore.setIdentity('BD')
})
</script>
<style scoped>
* {
color: rgba(0, 0, 0, 0.8);
font-family: 'SF Pro Text';
}
.overflow-y-auto {
overflow-y: auto;
}
.overflow-y-auto::-webkit-scrollbar {
display: none;
}
.bd-center {
max-height: 100vh;
overflow-y: auto;
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
background-color: #ffffff;
background-image: url(../../assets/images/secondBg.png);
}
.bd-center::-webkit-scrollbar {
display: none;
}
/* APP连接状态 */
.app-status {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
border-radius: 8px;
margin-bottom: 12px;
font-size: 12px;
font-weight: 500;
}
.app-status.connecting {
background-color: #fef3c7;
color: #d97706;
}
.status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: currentColor;
}
.app-status.connecting .status-indicator {
animation: pulse 1.5s ease-in-out infinite;
}
.salaryList::-webkit-scrollbar {
display: none;
}
@keyframes pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.5;
}
}
@media screen and (max-width: 360px) {
* {
font-size: 10px;
}
}
@media screen and (min-width: 360px) {
* {
font-size: 12px;
}
}
@media screen and (min-width: 768px) {
* {
font-size: 24px;
}
}
@media screen and (min-width: 1024px) {
* {
font-size: 32px;
}
}
/* RTL支持 */
[dir='rtl'] .avatar {
margin-right: 0;
margin-left: 12px;
}
[dir='rtl'] .user-info {
text-align: right;
}
[dir='rtl'] .flipImg {
transform: scaleX(-1);
}
</style>