aslan-h5/src/views/TeamBillView.vue
2025-08-15 13:12:36 +08:00

623 lines
12 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="team-bill gradient-background-circles">
<MobileHeader title="Team Bill" />
<div class="content">
<!-- 成员资料信息 -->
<!-- 工作报告标题 -->
<div class="work-report-title">
<span>Work report:</span>
<button class="help-btn" @click="showHelpInfo">?</button>
</div>
<!-- 加载状态 -->
<div v-if="loading" class="loading-container">
<div class="loading-spinner"></div>
<p>Loading...</p>
</div>
<!-- 账单列表 -->
<div v-else-if="billList.length > 0" class="bill-list">
<div
v-for="bill in billList"
:key="bill.id"
class="bill-item"
@click="showBillDetail(bill)"
>
<div class="bill-header">
<span class="bill-period">{{ bill.billTitle }}</span>
<span :class="['bill-status', getStatusClass(bill.status)]">
{{ getStatusText(bill.status) }}
</span>
</div>
<div class="bill-details">
<div class="bill-row">
<span class="bill-label">Host Salary:</span>
<span class="bill-value">${{ formatSalaryValue(bill.target?.ownSalary) }}</span>
</div>
<div class="bill-row">
<span class="bill-label">Agent Salary:</span>
<span class="bill-value">${{ formatSalaryValue(bill.target?.memberSalary) }}</span>
</div>
<div class="bill-row">
<span class="bill-label">Total Salary:</span>
<span class="bill-value total-salary-value">${{ formatSalaryValue(bill.target?.totalSalry) }}</span>
</div>
</div>
<div class="more-btn">
<span>More</span>
<span class="arrow">></span>
</div>
</div>
</div>
<!-- 空数据状态 -->
<div v-else class="empty-state">
<div class="empty-icon">📋</div>
<p>No data available</p>
</div>
</div>
<!-- 帮助模态框 -->
<div v-if="showHelpModal" class="modal-overlay" @click="closeHelpModal">
<div class="help-modal-content" @click.stop>
<div class="help-modal-header">
<h3>Work Report Help</h3>
<button class="close-btn" @click="closeHelpModal">×</button>
</div>
<div class="help-modal-body">
<div class="help-section">
<p class="help-description">
Below is the work report of the team members. Click "More" to view detailed daily work records.
</p>
</div>
<div class="help-section">
<h4>Status Description:</h4>
<div class="status-list">
<div class="status-item">
<span class="status-number">(1)</span>
<span class="status-name">UNPAID:</span>
<span class="status-desc">Work is currently in progress.</span>
</div>
<div class="status-item">
<span class="status-number">(2)</span>
<span class="status-name">HANG_UP:</span>
<span class="status-desc">Work has been suspended or is pending review.</span>
</div>
<div class="status-item">
<span class="status-number">(3)</span>
<span class="status-name">PAID:</span>
<span class="status-desc">Work has been completed and settled.</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 账单详情模态框 (使用 TeamBillMore 组件) -->
<div v-if="showDetailModal" class="modal-overlay">
<div class="detail-modal-wrapper">
<TeamBillMore
:billData="selectedBill"
@close="closeDetailModal"
@propsReceived="handlePropsReceived"
/>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import MobileHeader from '../components/MobileHeader.vue'
import TeamBillMore from '../components/team/TeamBillMore.vue'
import { getTeamMemberWork, formatDateDisplay } from '../api/teamBill.js'
const router = useRouter()
const loading = ref(false)
const showHelpModal = ref(false)
const showDetailModal = ref(false)
const selectedBill = ref(null)
// 数据
const memberProfile = ref(null)
const billList = ref([])
// 获取团队成员工作数据
const fetchTeamMemberWork = async (userId) => {
try {
loading.value = true
const response = await getTeamMemberWork(userId)
if (response.status && response.body) {
memberProfile.value = response.body.memberProfile
billList.value = response.body.targets || []
}
} catch (error) {
console.error('Failed to fetch team member work:', error)
} finally {
loading.value = 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 statusMap = {
'UNPAID': 'In Progress',
'HANG_UP': 'Pending',
'PAID': 'Completed'
}
return statusMap[status] || status
}
// 获取状态样式类
const getStatusClass = (status) => {
const statusClassMap = {
'UNPAID': 'in-progress',
'HANG_UP': 'pending',
'PAID': 'completed'
}
return statusClassMap[status] || 'unknown'
}
// 格式化日期
const formatDate = (dateNumber) => {
return formatDateDisplay(dateNumber)
}
// 显示账单详情
const showBillDetail = (bill) => {
selectedBill.value = bill
showDetailModal.value = true
}
// 关闭详情模态框
const closeDetailModal = () => {
showDetailModal.value = false
selectedBill.value = null
}
// 显示帮助模态框
const showHelpInfo = () => {
showHelpModal.value = true
}
// 关闭帮助模态框
const closeHelpModal = () => {
showHelpModal.value = false
}
// 处理道具领取成功
const handlePropsReceived = () => {
// 可以在这里添加提示或者刷新数据
console.log('Props received successfully')
}
// 组件挂载时获取数据
onMounted(() => {
// 从路由参数或者默认值获取用户ID
const userId = router.currentRoute.value.query.userId || '1911661502909562881'
fetchTeamMemberWork(userId)
})
</script>
<style scoped>
.team-bill {
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
min-height: 100vh;
background-color: #f1f2f3;
}
.content {
padding: 16px;
position: relative;
z-index: 2;
}
/* 成员资料卡片 */
.member-profile-card {
background-color: white;
padding: 16px;
border-radius: 12px;
margin-bottom: 16px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.member-info {
display: flex;
align-items: center;
gap: 12px;
}
.avatar-wrapper {
position: relative;
flex-shrink: 0;
}
.member-avatar {
width: 48px;
height: 48px;
border-radius: 8px;
object-fit: cover;
}
.country-flag {
position: absolute;
bottom: -4px;
left: 2px;
background-color: #333;
color: white;
font-size: 10px;
padding: 1px 3px;
border-radius: 2px;
}
.member-details {
flex: 1;
}
.member-name {
font-size: 16px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
}
.member-id {
font-size: 12px;
color: #666;
margin-bottom: 2px;
}
.member-status {
font-size: 12px;
color: #10B981;
}
/* 工作报告标题 */
.work-report-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
color: #666;
margin-bottom: 12px;
}
.help-btn {
width: 20px;
height: 20px;
border-radius: 10px;
background-color: #666;
color: white;
border: none;
font-size: 12px;
cursor: pointer;
transition: all 0.2s;
}
.help-btn:hover {
background-color: #8B5CF6;
}
/* 加载状态 */
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
color: #666;
}
.loading-spinner {
width: 32px;
height: 32px;
border: 3px solid #f3f3f3;
border-top: 3px solid #8B5CF6;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 账单列表 */
.bill-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.bill-item {
background-color: white;
padding: 16px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
cursor: pointer;
transition: all 0.2s;
}
.bill-item:active {
transform: scale(0.98);
}
.bill-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.bill-period {
font-size: 16px;
font-weight: 600;
color: #333;
}
.bill-status {
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-weight: 500;
}
.bill-status.in-progress {
background-color: #DBEAFE;
color: #1D4ED8;
}
.bill-status.pending {
background-color: #FEF3C7;
color: #D97706;
}
.bill-status.completed {
background-color: #D1FAE5;
color: #059669;
}
.bill-details {
margin-bottom: 12px;
}
.bill-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8px;
}
.bill-row:last-child {
margin-bottom: 0;
}
.bill-label {
font-size: 14px;
color: #666;
}
.bill-value {
font-size: 14px;
font-weight: 600;
color: #333;
}
.total-salary-value {
color: #059669 !important;
font-weight: 700;
}
.more-btn {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 4px;
color: #C084FC;
font-size: 14px;
cursor: pointer;
}
.arrow {
font-weight: bold;
}
/* 空数据状态 */
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 40px 20px;
color: #666;
}
.empty-icon {
font-size: 48px;
margin-bottom: 12px;
}
/* 模态框公共样式 */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 16px;
}
.help-modal-content,
.detail-modal-content {
background-color: white;
border-radius: 12px;
width: 100%;
max-width: 400px;
max-height: 80vh;
overflow: hidden;
display: flex;
flex-direction: column;
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #e5e7eb;
}
.modal-header h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #333;
}
.close-btn {
background: none;
border: none;
font-size: 24px;
cursor: pointer;
color: #666;
padding: 0;
width: 24px;
height: 24px;
display: flex;
align-items: center;
justify-content: center;
}
.modal-body {
padding: 16px;
overflow-y: auto;
}
/* 帮助模态框样式 */
.help-modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px;
border-bottom: 1px solid #e5e7eb;
background-color: #f8f9fa;
}
.help-modal-header h3 {
margin: 0;
font-size: 18px;
font-weight: 600;
color: #333;
}
.help-modal-body {
padding: 20px;
overflow-y: auto;
}
.help-section {
margin-bottom: 20px;
}
.help-section:last-child {
margin-bottom: 0;
}
.help-description {
font-size: 14px;
line-height: 1.5;
color: #555;
margin: 0;
padding: 12px;
background-color: #f0f9ff;
border-radius: 8px;
border-left: 4px solid #3b82f6;
}
.help-section h4 {
margin: 0 0 12px 0;
font-size: 16px;
font-weight: 600;
color: #333;
}
.status-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.status-item {
display: flex;
gap: 8px;
padding: 12px;
background-color: #f9fafb;
border-radius: 8px;
border: 1px solid #e5e7eb;
}
.status-number {
font-weight: 600;
color: #8B5CF6;
flex-shrink: 0;
}
.status-name {
font-weight: 600;
color: #333;
flex-shrink: 0;
min-width: 80px;
}
.status-desc {
color: #666;
line-height: 1.4;
flex: 1;
}
/* 详情模态框新样式 */
.detail-modal-wrapper {
width: 100%;
height: 100%;
max-width: 100vw;
max-height: 100vh;
overflow: auto;
background-color: white;
border-radius: 0;
}
/* 在大屏幕上显示为模态框 */
@media (min-width: 768px) {
.detail-modal-wrapper {
width: 90%;
height: 90%;
max-width: 600px;
max-height: 80vh;
border-radius: 12px;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
}
}
</style>