更新版

This commit is contained in:
tianfeng 2025-08-15 10:00:39 +08:00
parent a04b27b0c3
commit aa9c365cdf
7 changed files with 170 additions and 222 deletions

View File

@ -1,4 +1,4 @@
import { get, post } from '../utils/http.js' import {get, post} from '../utils/http.js'
/** /**
* 获取团队成员列表 * 获取团队成员列表
@ -147,14 +147,20 @@ export const processInviteMessage = async (data) => {
*/ */
export const getTeamMemberWork = async (userId) => { export const getTeamMemberWork = async (userId) => {
try { try {
const response = await get(`/team/member-work?userId=${userId}`) return await get(`/team/member-work?userId=${userId}`)
return response
} catch (error) { } catch (error) {
console.error('Failed to fetch team member work:', error) console.error('Failed to fetch team member work:', error)
throw error throw error
} }
} }
/**
* 用户申请记录查询
*/
export function getApplyRecord(userId, status) {
return get(`/team/user/apply/record?teamId=${userId}&status=${status}`)
}
/** /**
* 格式化显示状态 * 格式化显示状态
* @param {string} status - 状态值 * @param {string} status - 状态值

View File

@ -53,6 +53,14 @@ export function userBankSearchUserProfile(type, account) {
return get(`/wallet/bank/search/user-profile?type=${type}&account=${account}`) return get(`/wallet/bank/search/user-profile?type=${type}&account=${account}`)
} }
/**
* 获取用户身份信息
* @returns {Promise} 返回用户身份权限信息
*/
export function getUserIdentity() {
return get('/app/h5/1911661502909562881/identity')
}
/** /**
* 格式化时间戳为可读格式 * 格式化时间戳为可读格式
* @param {number} timestamp - 时间戳毫秒 * @param {number} timestamp - 时间戳毫秒

View File

@ -1,115 +1,79 @@
<template> <template>
<div class="team-bill-more"> <div class="team-bill-more">
<div class="bill-header"> <!-- 抽屉背景蒙层 -->
<h2>{{ billData?.billTitle }}</h2> <div class="drawer-overlay" @click="$emit('close')"></div>
<span :class="['bill-status', getStatusClass(billData?.status)]">
{{ getStatusText(billData?.status) }}
</span>
</div>
<!-- 账单汇总信息 --> <!-- 抽屉主体 -->
<div class="bill-summary-card"> <div class="drawer-content">
<h3>Summary</h3> <!-- 拖拽指示器 -->
<div class="summary-grid"> <div class="drag-indicator"></div>
<div class="summary-item">
<span class="summary-label">Gift Value:</span> <!-- 头部区域 -->
<span class="summary-value">{{ formatGiftValue(billData?.target?.acceptGiftValue) }}</span> <div class="bill-header">
</div> <h2>{{ billData?.billTitle }}</h2>
<div class="summary-item"> <div class="header-right">
<span class="summary-label">Online Time:</span> <span :class="['bill-status', getStatusClass(billData?.status)]">
<span class="summary-value">{{ formatOnlineTime(billData?.target?.onlineTime) }}</span> {{ getStatusText(billData?.status) }}
</div> </span>
<div class="summary-item"> <button class="close-btn" @click="$emit('close')">
<span class="summary-label">Diamond:</span> <span>×</span>
<span class="summary-value diamond-value">{{ formatDiamondValue(billData?.target?.acceptDiamondValue) }}</span> </button>
</div>
<div class="summary-item">
<span class="summary-label">Effective Days:</span>
<span class="summary-value">{{ billData?.target?.effectiveDay || 0 }}</span>
</div> </div>
</div> </div>
<!-- 结算结果如果已结算 --> <!-- 薪资汇总信息 -->
<div v-if="billData?.status === 'SETTLED' && billData?.target?.settlementResult" class="settlement-info"> <div class="bill-summary-card">
<div class="settlement-row"> <h3>Salary Summary</h3>
<span class="settlement-label">Target Level:</span> <div class="summary-grid">
<span class="settlement-value">{{ billData.target.settlementResult.level || '' }}</span> <div class="summary-item">
</div> <span class="summary-label">Host Salary:</span>
<div class="settlement-row"> <span class="summary-value">${{ formatSalaryValue(billData?.target?.ownSalary) }}</span>
<span class="settlement-label">Member Salary:</span>
<span class="settlement-value salary-value">${{ billData.target.settlementResult.memberSalary || 0 }}</span>
</div>
<!-- 道具奖励 -->
<div v-if="canReceivePropsReward(billData)" class="props-reward-section">
<div class="props-reward-header">
<span class="props-label">
{{ billData.target.settlementResult.propsReceived ? 'Props Received:' : 'Props Reward:' }}
</span>
<button
v-if="!billData.target.settlementResult.propsReceived"
class="receive-props-btn"
@click="receivePropsReward"
:disabled="receivingReward"
>
{{ receivingReward ? 'Receiving...' : 'Receive Props' }}
</button>
</div> </div>
<div class="props-list"> <div class="summary-item">
<div <span class="summary-label">Agent Salary:</span>
v-for="(prop, index) in billData.target.settlementResult.propsRewards" <span class="summary-value">${{ formatSalaryValue(billData?.target?.memberSalary) }}</span>
:key="index" </div>
class="prop-item" <div class="summary-item total-salary">
> <span class="summary-label">Total Salary:</span>
<div class="prop-info"> <span class="summary-value total-salary-value">${{ formatSalaryValue(billData?.target?.totalSalry) }}</span>
<span class="prop-name">{{ prop.name }}</span> </div>
<span class="prop-type">{{ prop.type }}</span> </div>
</div>
<!-- 每日薪资详情 -->
<div class="daily-details-card">
<h3>Daily Salary Details</h3>
<div v-if="billData?.target?.dailyTargets?.length > 0" class="daily-list">
<div
v-for="(daily, index) in billData.target.dailyTargets"
:key="index"
class="daily-item"
>
<div class="daily-header">
<span class="daily-date">{{ formatDate(daily.dateNumber) }}</span>
<span class="daily-time">{{ formatCreateTime(daily.createTime) }}</span>
</div>
<div class="daily-stats">
<div class="daily-stat">
<span class="stat-label">Host:</span>
<span class="stat-value">${{ formatSalaryValue(daily.ownSalary) }}</span>
</div>
<div class="daily-stat">
<span class="stat-label">Agent:</span>
<span class="stat-value">${{ formatSalaryValue(daily.memberSalary) }}</span>
</div>
<div class="daily-stat">
<span class="stat-label">Total:</span>
<span class="stat-value total-daily-value">${{ formatSalaryValue(daily.totalSalry) }}</span>
</div> </div>
<div class="prop-value">${{ prop.amount || 0 }}</div>
</div> </div>
</div> </div>
</div> </div>
</div> <div v-else class="no-daily-data">
</div> <div class="no-data-icon">💰</div>
<p>No daily salary data available</p>
<!-- 每日详情 -->
<div class="daily-details-card">
<h3>Daily Details</h3>
<div v-if="billData?.target?.dailyTargets?.length > 0" class="daily-list">
<div
v-for="(daily, index) in billData.target.dailyTargets"
:key="index"
class="daily-item"
>
<div class="daily-header">
<span class="daily-date">{{ formatDate(daily.dateNumber) }}</span>
<span class="daily-time">{{ formatCreateTime(daily.createTime) }}</span>
</div>
<div class="daily-stats">
<div class="daily-stat">
<span class="stat-label">Gift:</span>
<span class="stat-value">{{ formatGiftValue(daily.acceptGiftValue) }}</span>
</div>
<div class="daily-stat">
<span class="stat-label">Time:</span>
<span class="stat-value">{{ formatOnlineTime(daily.onlineTime) }}</span>
</div>
<div class="daily-stat">
<span class="stat-label">Diamond:</span>
<span class="stat-value diamond-value">{{ formatDiamondValue(daily.acceptDiamondValue) }}</span>
</div>
</div>
</div> </div>
</div> </div>
<div v-else class="no-daily-data">
<div class="no-data-icon">📅</div>
<p>No daily data available</p>
</div>
</div>
<!-- 关闭按钮 -->
<div class="close-button-container">
<button class="close-btn" @click="$emit('close')">Close</button>
</div> </div>
</div> </div>
</template> </template>
@ -117,12 +81,7 @@
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref, computed } from 'vue'
import { import {
formatGiftValue, formatDateDisplay
formatOnlineTime,
formatDiamondValue,
formatDateDisplay,
canReceivePropsReward,
receivePolicyPropsReward
} from '../../api/teamBill.js' } from '../../api/teamBill.js'
const props = defineProps({ const props = defineProps({
@ -132,9 +91,14 @@ const props = defineProps({
} }
}) })
const emit = defineEmits(['close', 'propsReceived']) const emit = defineEmits(['close'])
const receivingReward = ref(false) //
const formatSalaryValue = (value) => {
if (!value || value === '0' || value === 0) return '0.00'
const numValue = parseFloat(value)
return numValue.toFixed(2)
}
// //
const getStatusText = (status) => { const getStatusText = (status) => {
@ -173,30 +137,6 @@ const formatCreateTime = (timestamp) => {
minute: '2-digit' minute: '2-digit'
}) })
} }
//
const receivePropsReward = async () => {
if (!props.billData?.target?.id || receivingReward.value) {
return
}
try {
receivingReward.value = true
await receivePolicyPropsReward(props.billData.target.id)
//
if (props.billData.target.settlementResult) {
props.billData.target.settlementResult.propsReceived = true
}
emit('propsReceived')
} catch (error) {
console.error('Failed to receive props reward:', error)
alert('Failed to receive props reward. Please try again.')
} finally {
receivingReward.value = false
}
}
</script> </script>
<style scoped> <style scoped>

View File

@ -18,18 +18,6 @@
</button> </button>
</div> </div>
<!-- 身份切换标签 -->
<div class="identity-tabs">
<button
v-for="identity in identities"
:key="identity.value"
@click="handleIdentityChange(identity.value)"
:class="['identity-tab', { active: currentIdentity === identity.value }]"
>
{{ identity.label }}
</button>
</div>
<!-- 账户状态标签 --> <!-- 账户状态标签 -->
<div class="account-tags"> <div class="account-tags">
<span class="tag agency-tag">🏢 Agency</span> <span class="tag agency-tag">🏢 Agency</span>

View File

@ -20,18 +20,6 @@
</button> </button>
</div> </div>
<!-- 身份切换标签 -->
<div class="identity-tabs">
<button
v-for="identity in identities"
:key="identity.value"
@click="handleIdentityChange(identity.value)"
:class="['identity-tab', { active: currentIdentity === identity.value }]"
>
{{ identity.label }}
</button>
</div>
<!-- 账户状态标签 --> <!-- 账户状态标签 -->
<div class="account-tags"> <div class="account-tags">
<span class="tag host-tag">👑 Host</span> <span class="tag host-tag">👑 Host</span>
@ -129,7 +117,7 @@
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue' import MobileHeader from '../components/MobileHeader.vue'
import { getBankBalance } from '../api/wallet.js' import { getBankBalance, getUserIdentity } from '../api/wallet.js'
const router = useRouter() const router = useRouter()
@ -137,7 +125,7 @@ const router = useRouter()
const currentIdentity = ref('host') const currentIdentity = ref('host')
const loading = ref(false) const loading = ref(false)
// //
const identities = [ const identities = [
{ label: 'Host', value: 'host' }, { label: 'Host', value: 'host' },
{ label: 'Agency', value: 'agency' }, { label: 'Agency', value: 'agency' },
@ -207,23 +195,35 @@ const goToNotification = () => {
router.push('/host-setting') router.push('/host-setting')
} }
// //
const handleIdentityChange = (identity) => { const checkUserIdentity = async () => {
switch (identity) { try {
case 'agency': const response = await getUserIdentity()
router.push('/agency-center')
break if (response && response.status && response.body) {
case 'coin-seller': const { freightAgent, anchor, agent } = response.body
router.push('/coin-seller')
break // freightAgent > anchor > agent
case 'host': if (freightAgent) {
default: router.push('/coin-seller')
// } else if (anchor) {
currentIdentity.value = identity router.push('/agency-center')
break } else if (agent) {
// Host
currentIdentity.value = 'host'
} else {
// Host
currentIdentity.value = 'host'
}
}
} catch (error) {
console.error('获取用户身份失败:', error)
// Host
currentIdentity.value = 'host'
} }
} }
const exchangeGoldCoins = () => { const exchangeGoldCoins = () => {
router.push('/exchange-gold-coins') router.push('/exchange-gold-coins')
} }
@ -232,9 +232,10 @@ const transfer = () => {
router.push('/transfer') router.push('/transfer')
} }
// //
onMounted(() => { onMounted(() => {
fetchBankBalance() fetchBankBalance()
checkUserIdentity()
}) })
</script> </script>
@ -345,6 +346,21 @@ onMounted(() => {
color: #8B5CF6; color: #8B5CF6;
} }
.identity-tab.disabled {
cursor: not-allowed;
opacity: 0.6;
}
.identity-tab.disabled:hover {
border-color: #e5e7eb;
color: #666;
}
.identity-tab.disabled.active:hover {
border-color: #8B5CF6;
color: white;
}
.account-tags { .account-tags {
display: flex; display: flex;
gap: 8px; gap: 8px;

View File

@ -47,6 +47,7 @@
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue' import MobileHeader from '../components/MobileHeader.vue'
import { getApplyRecord } from '../api/teamBill.js'
const router = useRouter() const router = useRouter()
const loading = ref(false) const loading = ref(false)
@ -77,15 +78,13 @@ const mockMessages = [
// //
const fetchMessages = async () => { const fetchMessages = async () => {
loading.value = true loading.value = true
try { try {
// API const response = await getApplyRecord('1954059793963393025', 'WAIT') //
setTimeout(() => { // { data: [...] }
messages.value = mockMessages messages.value = response.data || response //
loading.value = false
}, 800)
} catch (error) { } catch (error) {
console.error('Failed to fetch messages:', error)
} finally {
loading.value = false loading.value = false
} }
} }

View File

@ -47,23 +47,18 @@
<div class="bill-details"> <div class="bill-details">
<div class="bill-row"> <div class="bill-row">
<span class="bill-label">Gift Value:</span> <span class="bill-label">Host Salary:</span>
<span class="bill-value">{{ formatGiftValue(bill.target?.acceptGiftValue) }}</span> <span class="bill-value">${{ formatSalaryValue(bill.target?.ownSalary) }}</span>
</div> </div>
<div class="bill-row"> <div class="bill-row">
<span class="bill-label">Online Time:</span> <span class="bill-label">Agent Salary:</span>
<span class="bill-value">{{ formatOnlineTime(bill.target?.onlineTime) }}</span> <span class="bill-value">${{ formatSalaryValue(bill.target?.memberSalary) }}</span>
</div> </div>
<div class="bill-row"> <div class="bill-row">
<span class="bill-label">Diamond:</span> <span class="bill-label">Total Salary:</span>
<span class="bill-value diamond-value">{{ formatDiamondValue(bill.target?.acceptDiamondValue) }}</span> <span class="bill-value total-salary-value">${{ formatSalaryValue(bill.target?.totalSalry) }}</span>
</div>
<div class="bill-row">
<span class="bill-label">Effective Days:</span>
<span class="bill-value">{{ bill.target?.effectiveDay || 0 }}</span>
</div> </div>
</div> </div>
@ -138,7 +133,7 @@ import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue' import MobileHeader from '../components/MobileHeader.vue'
import TeamBillMore from '../components/team/TeamBillMore.vue' import TeamBillMore from '../components/team/TeamBillMore.vue'
import { getTeamMemberWork, formatGiftValue, formatOnlineTime, formatDateDisplay } from '../api/teamBill.js' import { getTeamMemberWork, formatDateDisplay } from '../api/teamBill.js'
const router = useRouter() const router = useRouter()
const loading = ref(false) const loading = ref(false)
@ -167,6 +162,13 @@ const fetchTeamMemberWork = async (userId) => {
} }
} }
//
const formatSalaryValue = (value) => {
if (!value || value === '0' || value === 0) return '0.00'
const numValue = parseFloat(value)
return numValue.toFixed(2)
}
// //
const getStatusText = (status) => { const getStatusText = (status) => {
const statusMap = { const statusMap = {
@ -187,18 +189,6 @@ const getStatusClass = (status) => {
return statusClassMap[status] || 'unknown' return statusClassMap[status] || 'unknown'
} }
//
const formatDiamondValue = (value) => {
if (!value || value === '0') return '0'
const numValue = parseInt(value)
if (numValue >= 1000000) {
return `${(numValue / 1000000).toFixed(1)}M`
} else if (numValue >= 1000) {
return `${(numValue / 1000).toFixed(1)}K`
}
return numValue.toString()
}
// //
const formatDate = (dateNumber) => { const formatDate = (dateNumber) => {
return formatDateDisplay(dateNumber) return formatDateDisplay(dateNumber)
@ -444,8 +434,9 @@ onMounted(() => {
color: #333; color: #333;
} }
.diamond-value { .total-salary-value {
color: #1E40AF !important; color: #059669 !important;
font-weight: 700;
} }
.more-btn { .more-btn {