|
|
|
@ -20,10 +20,10 @@ |
|
|
|
<!-- 数据概览 --> |
|
|
|
<div v-show="activeTab === 'overview'" class="tab-content overview-content"> |
|
|
|
<div class="stats-row"> |
|
|
|
<!-- 用户总数 --> |
|
|
|
<!-- 用户总数和登录总数 --> |
|
|
|
<div class="stat-card purple-gradient big-card"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><UserFilled /></el-icon> 用户总数 |
|
|
|
<el-icon><UserFilled /></el-icon> 用户注册总数 |
|
|
|
</div> |
|
|
|
<div class="big-card-content"> |
|
|
|
<div class="card-value">{{ overviewData.total }}</div> |
|
|
|
@ -31,49 +31,73 @@ |
|
|
|
{{ getGrowthText(overviewData.total_growth) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><View /></el-icon> 用户登录总数 |
|
|
|
</div> |
|
|
|
<div class="big-card-content"> |
|
|
|
<div class="card-value">{{ overviewData.total_login }}</div> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.total_login_growth)"> |
|
|
|
{{ getGrowthText(overviewData.total_login_growth) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<div class="right-stats-col"> |
|
|
|
<!-- 会员总数 --> |
|
|
|
<div class="stat-card orange-gradient small-card"> |
|
|
|
<div class="left-part"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><Trophy /></el-icon> 会员总数 |
|
|
|
<div class="small-card-content"> |
|
|
|
<div class="left-part"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><Trophy /></el-icon> 会员总数 |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="right-part"> |
|
|
|
<div class="card-value-small">{{ overviewData.member }}</div> |
|
|
|
<div class="card-tag-wrapper"> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.member_growth)"> |
|
|
|
{{ getGrowthText(overviewData.member_growth) }} |
|
|
|
<div class="right-part"> |
|
|
|
<div class="card-value-small">{{ overviewData.member }}</div> |
|
|
|
<div class="card-tag-wrapper"> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.member_growth)"> |
|
|
|
{{ getGrowthText(overviewData.member_growth) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 非会员总数 --> |
|
|
|
<!-- 非网注册和登录总数 --> |
|
|
|
<div class="stat-card blue-gradient small-card"> |
|
|
|
<div class="left-part"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><User /></el-icon> 非会员总数 |
|
|
|
<div class="small-card-row"> |
|
|
|
<!-- 非网注册总数 --> |
|
|
|
<div class="small-card-item"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><User /></el-icon> 非网注册总数 |
|
|
|
</div> |
|
|
|
<div class="card-value-small">{{ overviewData.normal_register }}</div> |
|
|
|
<div class="card-tag-wrapper"> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.normal_reg_growth)"> |
|
|
|
{{ getGrowthText(overviewData.normal_reg_growth) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="right-part"> |
|
|
|
<div class="card-value-small">{{ overviewData.normal }}</div> |
|
|
|
<div class="card-tag-wrapper"> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.normal_growth)"> |
|
|
|
{{ getGrowthText(overviewData.normal_growth) }} |
|
|
|
</div> |
|
|
|
<!-- 非网登录总数 --> |
|
|
|
<div class="small-card-item"> |
|
|
|
<div class="card-title"> |
|
|
|
<el-icon><View /></el-icon> 非网登录总数 |
|
|
|
</div> |
|
|
|
<div class="card-value-small">{{ overviewData.normal_login }}</div> |
|
|
|
<div class="card-tag-wrapper"> |
|
|
|
<div class="card-tag" :class="getGrowthClass(overviewData.normal_login_growth)"> |
|
|
|
{{ getGrowthText(overviewData.normal_login_growth) }} |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
<!-- 用户构成比例 --> |
|
|
|
<!-- 登录用户构成比例 --> |
|
|
|
<div class="composition-section"> |
|
|
|
<div class="section-header"> |
|
|
|
<el-icon><PieChart /></el-icon> 用户构成比例 |
|
|
|
<el-icon><PieChart /></el-icon> 登录用户构成比例 |
|
|
|
</div> |
|
|
|
<div class="charts-row"> |
|
|
|
<div class="chart-wrapper"> |
|
|
|
@ -217,12 +241,23 @@ let chartBarInstance = null; |
|
|
|
const overviewData = ref({ |
|
|
|
total: 0, |
|
|
|
total_growth: '0%', |
|
|
|
total_login: 0, |
|
|
|
total_login_growth: '0%', |
|
|
|
member: 0, |
|
|
|
member_growth: '0%', |
|
|
|
normal: 0, |
|
|
|
normal_growth: '0%', |
|
|
|
new_normal: 0, |
|
|
|
old_normal: 0 |
|
|
|
normal_register: 0, |
|
|
|
normal_reg_growth: '0%', |
|
|
|
normal_login: 0, |
|
|
|
normal_login_growth: '0%', |
|
|
|
group_member_normal: { |
|
|
|
member_val: 0, |
|
|
|
normal_login_val: 0 |
|
|
|
}, |
|
|
|
group_triple: { |
|
|
|
member_val: 0, |
|
|
|
new_normal_login_val: 0, |
|
|
|
old_normal_val: 0 |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// 表格数据 - 使用 ref 响应式数据 |
|
|
|
@ -428,8 +463,8 @@ const initCharts = () => { |
|
|
|
avoidLabelOverlap: false, |
|
|
|
label: { show: false }, |
|
|
|
data: [ |
|
|
|
{ value: overviewData.value.normal, name: '非会员用户' }, |
|
|
|
{ value: overviewData.value.member, name: '会员用户' } |
|
|
|
{ value: overviewData.value.group_member_normal.normal_login_val, name: '非会员用户' }, |
|
|
|
{ value: overviewData.value.group_member_normal.member_val, name: '会员用户' } |
|
|
|
] |
|
|
|
} |
|
|
|
] |
|
|
|
@ -456,9 +491,9 @@ const initCharts = () => { |
|
|
|
avoidLabelOverlap: false, |
|
|
|
label: { show: false }, |
|
|
|
data: [ |
|
|
|
{ value: overviewData.value.new_normal, name: '新非网数量' }, |
|
|
|
{ value: overviewData.value.member, name: '会员用户' }, |
|
|
|
{ value: overviewData.value.old_normal, name: '老非网数量' } |
|
|
|
{ value: overviewData.value.group_triple.new_normal_login_val, name: '新非网数量' }, |
|
|
|
{ value: overviewData.value.group_triple.member_val, name: '会员用户' }, |
|
|
|
{ value: overviewData.value.group_triple.old_normal_val, name: '老非网数量' } |
|
|
|
] |
|
|
|
} |
|
|
|
] |
|
|
|
@ -607,7 +642,7 @@ onMounted(() => { |
|
|
|
padding: 24px; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
justify-content: flex-start; /* 从顶部开始布局 */ |
|
|
|
justify-content: space-between; /* 空间分布 */ |
|
|
|
color: #fff; |
|
|
|
position: relative; /* 确保绝对定位相对于卡片 */ |
|
|
|
} |
|
|
|
@ -634,11 +669,42 @@ onMounted(() => { |
|
|
|
border-radius: 12px; |
|
|
|
padding: 20px; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
justify-content: center; |
|
|
|
color: #fff; |
|
|
|
position: relative; /* 确保绝对定位相对于卡片 */ |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-row { |
|
|
|
display: flex; |
|
|
|
flex-direction: row; |
|
|
|
justify-content: space-between; |
|
|
|
height: 100%; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-item { |
|
|
|
flex: 1; |
|
|
|
display: flex; |
|
|
|
flex-direction: column; |
|
|
|
align-items: center; |
|
|
|
color: #fff; |
|
|
|
position: relative; /* 确保绝对定位相对于卡片 */ |
|
|
|
justify-content: center; |
|
|
|
padding: 0 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-item:first-child { |
|
|
|
border-right: 1px solid rgba(255, 255, 255, 0.3); |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-content { |
|
|
|
display: flex; |
|
|
|
flex-direction: row; |
|
|
|
justify-content: space-between; |
|
|
|
align-items: center; |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-content:last-child { |
|
|
|
margin-bottom: 0; |
|
|
|
} |
|
|
|
|
|
|
|
.left-part { |
|
|
|
@ -667,7 +733,17 @@ onMounted(() => { |
|
|
|
|
|
|
|
.small-card .card-title { |
|
|
|
width: auto; |
|
|
|
margin-bottom: 0; |
|
|
|
margin-bottom: 10px; |
|
|
|
text-align: center; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-item .card-title { |
|
|
|
font-size: 24px; |
|
|
|
margin-bottom: 15px; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-item .card-value-small { |
|
|
|
margin-bottom: 10px; |
|
|
|
} |
|
|
|
|
|
|
|
.card-value { |
|
|
|
@ -708,6 +784,12 @@ onMounted(() => { |
|
|
|
|
|
|
|
.small-card .card-tag-wrapper { |
|
|
|
margin-top: 8px; |
|
|
|
display: flex; |
|
|
|
justify-content: center; |
|
|
|
} |
|
|
|
|
|
|
|
.small-card-item .card-tag-wrapper { |
|
|
|
margin-top: 8px; |
|
|
|
} |
|
|
|
.card-tag { |
|
|
|
background-color: #fff; |
|
|
|
|