style(组件): 团队账单的弹窗组件
This commit is contained in:
parent
fdb3f2e856
commit
9e82f2c93d
@ -1,98 +1,250 @@
|
||||
<template>
|
||||
<div class="team-bill-more">
|
||||
<!-- 头部区域 -->
|
||||
<div class="bill-header">
|
||||
<h2>{{ billData?.billTitle || 'Team Bill Details' }}</h2>
|
||||
<div class="header-right">
|
||||
<span :class="['bill-status', getStatusClass(billData?.status)]">
|
||||
<div
|
||||
style="
|
||||
background: white;
|
||||
border-radius: 16px 16px 0 0;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
padding: 20px;
|
||||
"
|
||||
>
|
||||
<!-- 标题 -->
|
||||
<div style="display: flex; justify-content: center; align-items: center">
|
||||
<div style="margin: 0; font-size: 18px; font-weight: 600; color: #333">Member income</div>
|
||||
</div>
|
||||
|
||||
<!-- 日期和类型 -->
|
||||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||||
<div style="color: rgba(0, 0, 0, 0.5); font-weight: 600; font-size: 1.3em">
|
||||
{{ billData?.date }}
|
||||
</div>
|
||||
<div
|
||||
style="margin: 4px; padding: 0 8px; border-radius: 4px; display: flex; align-items: center"
|
||||
:style="{ boxShadow }"
|
||||
>
|
||||
<div style="font-weight: 500" :style="{ color }">
|
||||
{{ getStatusText(billData?.status) }}
|
||||
</span>
|
||||
<button class="close-btn" @click="$emit('close')">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 成员列表 -->
|
||||
<div class="members-container">
|
||||
<div v-if="loading" class="loading-container">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading members...</p>
|
||||
</div>
|
||||
<!-- 搜索框 -->
|
||||
<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px">
|
||||
<div
|
||||
style="
|
||||
flex: 1;
|
||||
border-radius: 32px;
|
||||
border: 1px solid #fff;
|
||||
|
||||
<div v-else-if="members && members.length > 0" class="members-list">
|
||||
<div
|
||||
v-for="(member, index) in members"
|
||||
:key="member.memberProfile?.id || index"
|
||||
class="member-item"
|
||||
>
|
||||
<!-- 用户头像 -->
|
||||
<div class="member-avatar">
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25);
|
||||
padding: 0 8px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: max-content;
|
||||
"
|
||||
>
|
||||
<img src="../../assets/icon/search.png" alt="" width="24px" style="opacity: 0.6" />
|
||||
<input
|
||||
type="text"
|
||||
name=""
|
||||
id=""
|
||||
placeholder="Please enter the host lD"
|
||||
style="
|
||||
width: 100%;
|
||||
outline: none;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
color: black;
|
||||
padding: 10px 8px;
|
||||
"
|
||||
v-model="targetUserId"
|
||||
/>
|
||||
</div>
|
||||
<div style="font-weight: 600">Cancel</div>
|
||||
</div>
|
||||
|
||||
<!-- 加载成员 -->
|
||||
<div v-if="loading" class="loading-container">
|
||||
<div class="loading-spinner"></div>
|
||||
<p>Loading members...</p>
|
||||
</div>
|
||||
|
||||
<!-- 成员列表 -->
|
||||
<div v-if="members && members.length > 0" class="members-list">
|
||||
<div
|
||||
v-for="(member, index) in members"
|
||||
:key="member.memberProfile?.id || index"
|
||||
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="width: 75%; display: flex; align-items: center; justify-content: space-around">
|
||||
<!-- 头像 -->
|
||||
<div
|
||||
style="
|
||||
position: relative;
|
||||
margin-right: 4px;
|
||||
|
||||
width: 20%;
|
||||
aspect-ratio: 1/1;
|
||||
border-radius: 50%;
|
||||
|
||||
background-color: #8b5cf6;
|
||||
color: white;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
"
|
||||
>
|
||||
<img
|
||||
v-if="member.memberProfile?.userAvatar"
|
||||
:src="member.memberProfile.userAvatar"
|
||||
:alt="member.memberProfile?.userNickname"
|
||||
@error="handleImageError"
|
||||
style="width: 100%; height: 100%; border-radius: 50%; object-fit: cover"
|
||||
/>
|
||||
<div v-else class="avatar-placeholder">
|
||||
<div
|
||||
v-else
|
||||
style="
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-transform: uppercase;
|
||||
"
|
||||
>
|
||||
{{ getAvatarPlaceholder(member.memberProfile?.userNickname) }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- 账号信息 -->
|
||||
<div style="width: 30%; display: flex; flex-direction: column; gap: 4px">
|
||||
<div
|
||||
style="
|
||||
font-weight: 700;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
{{ member.memberProfile?.userNickname || 'Unknown User' }}
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
font-weight: 500;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
ID: {{ member.memberProfile?.account || 'N/A' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 用户信息区域 -->
|
||||
<div class="member-details">
|
||||
<!-- 左侧:用户信息 -->
|
||||
<div class="user-info">
|
||||
<div class="user-name">{{ member.memberProfile?.userNickname || 'Unknown User' }}</div>
|
||||
<div class="user-id">ID: {{ member.memberProfile?.account || 'N/A' }}</div>
|
||||
<div class="user-target">
|
||||
<span :class="['target-badge', getTargetClass(member.target?.acceptGiftValue)]">
|
||||
{{ formatTargetDisplay(member.target?.acceptGiftValue) }}
|
||||
</span>
|
||||
<!-- 等级信息 -->
|
||||
<div style="display: flex; align-items: center">
|
||||
<div
|
||||
style="
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(
|
||||
152deg,
|
||||
rgba(198, 112, 255, 0.6) 7.01%,
|
||||
rgba(119, 38, 255, 0.6) 92.99%
|
||||
);
|
||||
color: #fff;
|
||||
padding: 2px 8px;
|
||||
font-weight: 500;
|
||||
border: 1px solid #d1d5db;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
"
|
||||
>
|
||||
{{ formatTargetDisplay(member.target?.acceptGiftValue) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据区域 -->
|
||||
<div style="width: 25%; display: flex; justify-content: flex-end">
|
||||
<div style="width: 100%; display: flex; flex-direction: column">
|
||||
<div style="width: 100%; display: flex; align-items: center">
|
||||
<img src="../../assets/icon/coin.png" alt="" height="16px" style="display: block" />
|
||||
<div
|
||||
style="
|
||||
color: #ffb627;
|
||||
font-weight: 510;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
"
|
||||
>
|
||||
{{ formatDiamondValue(member.target?.acceptGiftValue) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:统计信息 -->
|
||||
<div class="member-stats">
|
||||
<div class="diamond-info">
|
||||
<span class="diamond-icon">🪙</span>
|
||||
<span class="diamond-value">{{ formatDiamondValue(member.target?.acceptGiftValue) }}</span>
|
||||
</div>
|
||||
<div class="time-info">
|
||||
<span class="time-label">Time (Days):</span>
|
||||
<span class="time-value">{{ Math.floor(member.target.onlineTime / 60 / 2, 0) }}</span>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
font-weight: 510;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: 100%;
|
||||
font-size: 0.9em;
|
||||
"
|
||||
>
|
||||
Time (Days):{{ Math.floor(member.target.onlineTime / 60 / 2, 0) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-else class="empty-state">
|
||||
<div class="empty-icon">👥</div>
|
||||
<p>No members data available</p>
|
||||
</div>
|
||||
<div v-else class="empty-state">
|
||||
<div class="empty-icon">👥</div>
|
||||
<p>No members data available</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import { ref, computed, onMounted, watch } from 'vue'
|
||||
import { formatBillStatus, getTeamReleasePolicy } from '../../api/teamBill.js'
|
||||
import { getTeamId } from '../../utils/userStore.js'
|
||||
|
||||
const props = defineProps({
|
||||
billData: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const emit = defineEmits(['close'])
|
||||
|
||||
const loading = ref(false)
|
||||
const policyData = ref(null)
|
||||
const loadingPolicy = ref(false)
|
||||
|
||||
const targetUserId = ref('') //搜索目标id
|
||||
|
||||
// 样式
|
||||
const color = ref('')
|
||||
const boxShadow = ref('')
|
||||
|
||||
// 从 billData 中获取成员数据
|
||||
const members = computed(() => {
|
||||
return props.billData?.members || []
|
||||
@ -136,8 +288,8 @@ const getTargetLevel = (giftValue) => {
|
||||
return parseFloat(b.target) - parseFloat(a.target)
|
||||
})
|
||||
|
||||
console.log('sortedPolicy', JSON.stringify(sortedPolicy))
|
||||
console.log('numValue', JSON.stringify(numValue))
|
||||
// console.log('sortedPolicy', JSON.stringify(sortedPolicy))
|
||||
// console.log('numValue', JSON.stringify(numValue))
|
||||
|
||||
for (const policy of sortedPolicy) {
|
||||
if (numValue >= parseFloat(policy.target)) {
|
||||
@ -146,7 +298,7 @@ const getTargetLevel = (giftValue) => {
|
||||
}
|
||||
|
||||
// 如果都不匹配,返回最低等级
|
||||
const minLevel = Math.min(...policyData.value.policy.map(p => p.level))
|
||||
const minLevel = Math.min(...policyData.value.policy.map((p) => p.level))
|
||||
return minLevel
|
||||
}
|
||||
|
||||
@ -157,23 +309,9 @@ const formatTargetDisplay = (giftValue) => {
|
||||
}
|
||||
|
||||
const level = getTargetLevel(giftValue)
|
||||
return `Level ${level}`
|
||||
return `Target: ${level}`
|
||||
}
|
||||
|
||||
// 获取Target等级样式
|
||||
const getTargetClass = (giftValue) => {
|
||||
const level = getTargetLevel(giftValue)
|
||||
if (typeof level === 'number') {
|
||||
return `target-level-${level}`
|
||||
}
|
||||
return 'target-default'
|
||||
}
|
||||
|
||||
// 组件挂载时获取政策数据
|
||||
onMounted(() => {
|
||||
fetchPolicyData()
|
||||
})
|
||||
|
||||
// 格式化状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusInfo = formatBillStatus(status)
|
||||
@ -225,30 +363,51 @@ const handleImageError = (event) => {
|
||||
console.warn('头像加载失败:', event.target.src)
|
||||
// 可以在这里设置默认头像
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.billData?.status,
|
||||
(status) => {
|
||||
console.log('status:', status)
|
||||
|
||||
let newStatus = getStatusText(status)
|
||||
if (newStatus == 'In Progress') {
|
||||
boxShadow.value = '0 0 1px 0 #6085FF'
|
||||
color.value = 'rgba(61, 115, 255, 1)'
|
||||
}
|
||||
if (newStatus == 'Pending') {
|
||||
boxShadow.value = '0 0 1px 0 #FF6062'
|
||||
color.value = 'rgba(255, 61, 64, 1)'
|
||||
}
|
||||
if (newStatus == 'Completed') {
|
||||
boxShadow.value = '0 0 1px 0 #60FF65'
|
||||
color.value = 'rgba(61, 255, 84, 1)'
|
||||
}
|
||||
if (newStatus == 'Out Of Account') {
|
||||
boxShadow.value = '0 0 1px 0 #6A6161'
|
||||
color.value = 'rgba(174, 174, 174, 1)'
|
||||
}
|
||||
return
|
||||
},
|
||||
{
|
||||
immediate: true,
|
||||
}
|
||||
)
|
||||
|
||||
// 组件挂载时获取政策数据
|
||||
onMounted(() => {
|
||||
fetchPolicyData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.team-bill-more {
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
font-family: -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
* {
|
||||
color: rgba(0, 0, 0, 0.8);
|
||||
font-family: 'SF Pro Text';
|
||||
}
|
||||
|
||||
/* 头部区域 */
|
||||
.bill-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 16px 20px;
|
||||
background-color: white;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
}
|
||||
|
||||
.bill-header h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
input::placeholder {
|
||||
font-weight: bold;
|
||||
color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.header-right {
|
||||
@ -265,34 +424,20 @@ const handleImageError = (event) => {
|
||||
}
|
||||
|
||||
.bill-status.in-progress {
|
||||
background-color: #DBEAFE;
|
||||
color: #1D4ED8;
|
||||
background-color: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.bill-status.pending {
|
||||
background-color: #FEF3C7;
|
||||
color: #D97706;
|
||||
background-color: #fef3c7;
|
||||
color: #d97706;
|
||||
}
|
||||
|
||||
.bill-status.completed {
|
||||
background-color: #D1FAE5;
|
||||
background-color: #d1fae5;
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
/* 成员列表容器 */
|
||||
.members-container {
|
||||
padding: 8px;
|
||||
@ -301,7 +446,7 @@ const handleImageError = (event) => {
|
||||
.members-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
/* 成员项目 */
|
||||
@ -348,7 +493,7 @@ const handleImageError = (event) => {
|
||||
.avatar-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #8B5CF6;
|
||||
background-color: #8b5cf6;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@ -385,58 +530,6 @@ const handleImageError = (event) => {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.user-target {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.target-badge {
|
||||
background-color: #f3f4f6;
|
||||
color: #374151;
|
||||
padding: 2px 8px;
|
||||
border-radius: 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
border: 1px solid #d1d5db;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* 不同等级的颜色样式 */
|
||||
.target-level-1 {
|
||||
background-color: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
border-color: #93c5fd;
|
||||
}
|
||||
|
||||
.target-level-2 {
|
||||
background-color: #dcfce7;
|
||||
color: #166534;
|
||||
border-color: #86efac;
|
||||
}
|
||||
|
||||
.target-level-3 {
|
||||
background-color: #fef3c7;
|
||||
color: #92400e;
|
||||
border-color: #fbbf24;
|
||||
}
|
||||
|
||||
.target-level-4 {
|
||||
background-color: #ede9fe;
|
||||
color: #6b21a8;
|
||||
border-color: #c4b5fd;
|
||||
}
|
||||
|
||||
.target-level-5 {
|
||||
background-color: #fce7f3;
|
||||
color: #be185d;
|
||||
border-color: #f9a8d4;
|
||||
}
|
||||
|
||||
.target-default {
|
||||
background-color: #f3f4f6;
|
||||
color: #6b7280;
|
||||
border-color: #d1d5db;
|
||||
}
|
||||
|
||||
/* 右侧统计信息 */
|
||||
.member-stats {
|
||||
display: flex;
|
||||
@ -490,15 +583,19 @@ const handleImageError = (event) => {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #8B5CF6;
|
||||
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); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 空数据状态 */
|
||||
@ -533,4 +630,22 @@ const handleImageError = (event) => {
|
||||
align-items: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user