ylj20011123 309cdacdc9 update
2025-11-18 17:52:08 +08:00

448 lines
14 KiB
Vue

<template>
<view class="member-mall">
<view class="section-header">
<text class="section-title">会员商城</text>
</view>
<!-- 会员总数 -->
<view class="member-sum-box">
<view class="member-sum-box-left">会员总数</view>
<view class="member-sum-total">{{ memberData.totalMembers ? memberData.totalMembers.toLocaleString() : 0 }}
</view>
<view class="member-sum-box-right">本月新增 {{ memberData.monthNewMembers ?
memberData.monthNewMembers.toLocaleString() : 0 }} </view>
</view>
<!-- 近30天数据 -->
<view class="section-header">
<text class="section-title">近30天数据</text>
</view>
<view class="recent-data">
<view class="recent-data-top">
<view class="recent-data-top-item" style="left: 0;top: 0;">
<view class="recent-data-top-value">{{ memberData.newMembersCount ?
memberData.newMembersCount.toLocaleString() : 0
}}
</view>
<view class="recent-data-top-label">新增会员数</view>
</view>
<view class="recent-data-top-item" style="left: 30%;top: 0;">
<view class="recent-data-top-value">{{ memberData.openCount ? memberData.openCount.toLocaleString()
: 0 }}</view>
<view class="recent-data-top-label">打开次数</view>
</view>
<view class="recent-data-top-item" style="right: 30%;top: 0;">
<view class="recent-data-top-value">{{ memberData.newPeopleCount ?
memberData.newPeopleCount.toLocaleString() : 0 }}
</view>
<view class="recent-data-top-label">新增人数</view>
</view>
<view class="recent-data-top-item" style="right: 0;top: 0;">
<view class="recent-data-top-value">{{ memberData.visitCount ?
memberData.visitCount.toLocaleString() : 0 }}</view>
<view class="recent-data-top-label">访问人数</view>
</view>
</view>
</view>
<!-- 会员消费情况 -->
<view class="section-header">
<text class="section-title">会员消费情况</text>
</view>
<view class="member-consumption">
<view class="member-consumption-item">
<view class="member-consumption-label">会员消费笔数/</view>
<view class="member-consumption-progress"></view>
<view class="member-consumption-value">{{ memberData.consumptionCount ? memberData.consumptionCount : 0
}}</view>
</view>
<view class="member-consumption-item">
<view class="member-consumption-label">会员总销售额/</view>
<view class="member-consumption-progress2"></view>
<view class="member-consumption-value">{{ memberData.totalSalesAmount }}</view>
</view>
</view>
<view class="member-content-box">
<view class="member-content-box-item">
<view class="member-content-box-item-box">
<view class="member-content-box-item-label">工会会员</view>
<view class="member-content-box-item-value">{{ memberData.unionMembers || 0 }}</view>
</view>
<view class="member-content-box-item-box" style="margin-top: 18px;">
<view class="member-content-box-item-label">会员占比</view>
<view class="member-content-box-item-value">{{ (memberData.memberRatio || 0) + '%' }}</view>
</view>
</view>
<view class="member-content-box-item">
<view class="member-content-box-item-box">
<view class="member-content-box-item-label">会员转化率</view>
<view class="member-content-box-item-value">{{ (memberData.conversionRate || 0) + '%' }}</view>
</view>
<view class="member-content-box-item-box" style="margin-top: 18px;">
<view class="member-content-box-item-label">会员增长率</view>
<view class="member-content-box-item-value">{{ (memberData.growthRate || 0) + '%' }}</view>
</view>
</view>
</view>
<!-- 会员消费数据概览 -->
<view class="section-header">
<text class="section-title">会员消费数据概览</text>
</view>
<view class="member-overview">
<view class="member-overview-item">
<view class="member-overview-item-top">{{ memberData.buyPeopleCount || 0 }}</view>
<view class="member-overview-item-bottom">购买人数</view>
</view>
<view class="member-overview-item">
<view class="member-overview-item-top">{{ memberData.avgAmount || 0 }}</view>
<view class="member-overview-item-bottom">人均消费</view>
</view>
<view class="member-overview-item">
<view class="member-overview-item-top">{{ (memberData.repurchaseRate || 0) }}</view>
<view class="member-overview-item-bottom">客单价</view>
</view>
<view class="member-overview-item">
<view class="member-overview-item-top">{{ (memberData.totalAmount || 0) + '%' }}</view>
<view class="member-overview-item-bottom">会员复购率</view>
</view>
</view>
</view>
</template>
<script>
import request from "@/util/index.js";
import moment from 'moment'
export default {
data() {
return {
memberData: {
totalMembers: 0,
monthNewMembers: 0,
newMembersCount: 0,
openCount: 0,
newPeopleCount: 0,
visitCount: 0,
consumptionCount: 0,
totalSalesAmount: 0,
unionMembers: 0,
memberRatio: 0,
conversionRate: 0,
growthRate: 0,
buyPeopleCount: 0,
avgAmount: 0,
repurchaseRate: 0,
totalAmount: 0
}
}
},
props: {
selectTime: {
type: String,
default: ""
},
},
watch: {
selectTime: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
this.handleGetMemberMallData()
}
},
immediate: false
}
},
onReady() {
this.handleGetMemberMallData()
},
methods: {
// 获取会员商城数据
async handleGetMemberMallData() {
const req = {
ProvinceCode: '530000',
StatisticsDate: this.selectTime ? moment(this.selectTime).subtract(1, 'd').format('YYYY-MM-DD') : moment().subtract(1, 'd').format('YYYY-MM-DD')
}
const data = await this.getMemberMallData(req);
// 处理数据
this.processChartData(data)
},
// 发起API请求获取会员商城数据
async getMemberMallData(params) {
// 写死数据返回
const mockData = {
totalMembers: 15071,
monthNewMembers: 146,
newMembersCount: 270,
openCount: 3203,
newPeopleCount: 757,
visitCount: 1914,
consumptionCount: 104,
totalSalesAmount: '47, 550.60',
unionMembers: 1782,
memberRatio: 11.82,
conversionRate: 32.17,
growthRate: 0.97,
buyPeopleCount: 99,
avgAmount: 480.31,
repurchaseRate: 461.66,
totalAmount: 2.02
}
return mockData || {}
},
// 处理图表数据
processChartData(data) {
// 更新数据
this.memberData = {
totalMembers: data.totalMembers || 0,
monthNewMembers: data.monthNewMembers || 0,
newMembersCount: data.newMembersCount || 0,
openCount: data.openCount || 0,
newPeopleCount: data.newPeopleCount || 0,
visitCount: data.visitCount || 0,
consumptionCount: data.consumptionCount || 0,
totalSalesAmount: data.totalSalesAmount || 0,
unionMembers: data.unionMembers || 0,
memberRatio: data.memberRatio || 0,
conversionRate: data.conversionRate || 0,
growthRate: data.growthRate || 0,
buyPeopleCount: data.buyPeopleCount || 0,
avgAmount: data.avgAmount || 0,
repurchaseRate: data.repurchaseRate || 0,
totalAmount: data.totalAmount || 0
}
},
// 格式化金额
formatMoney(amount) {
if (!amount || amount === 0) return '0.00'
return Number(amount).toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
}
}
}
</script>
<style scoped lang="less">
@text-primary: #333;
@text-secondary: #666;
@bg-white: #ffffff;
.member-mall {
width: 100%;
.member-sum-box {
background: #fff;
border-radius: 16rpx;
padding: 18rpx 24rpx;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-bottom: 24rpx;
display: flex;
align-items: center;
justify-content: space-between;
.member-sum-box-left {
font-size: 24rpx;
font-weight: 600;
color: @text-primary;
}
.member-sum-total {
font-size: 28rpx;
font-weight: 600;
color: #1890FF;
}
.member-sum-box-right {
font-size: 24rpx;
font-weight: 400;
color: @text-secondary;
text-align: right;
}
}
.section-header {
margin-bottom: 12rpx;
.section-title {
font-size: 30rpx;
font-weight: 600;
color: @text-primary;
}
}
.recent-data {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-bottom: 24rpx;
height: 136rpx;
.recent-data-top {
width: 100%;
height: 136rpx;
position: relative;
.recent-data-top-item {
position: absolute;
display: flex;
flex-direction: column;
align-items: center;
.recent-data-top-value {
width: 88rpx;
height: 88rpx;
font-size: 28rpx;
color: #fff;
line-height: 88rpx;
text-align: center;
background: linear-gradient(135deg, #1890ff 0%, #46B8F3 100%);
border-radius: 50%;
box-shadow: 0 4rpx 12rpx rgba(24, 144, 255, 0.3);
}
.recent-data-top-label {
font-size: 24rpx;
color: @text-secondary;
line-height: 36rpx;
text-align: center;
margin-top: 10rpx;
}
}
}
}
.member-content-box {
display: flex;
gap: 24rpx;
margin-bottom: 32rpx;
.member-content-box-item {
flex: 1;
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
text-align: center;
.member-content-box-item-box {
margin-bottom: 18rpx;
&:last-child {
margin-bottom: 0;
}
.member-content-box-item-label {
font-size: 24rpx;
color: @text-primary;
margin-bottom: 8rpx;
}
.member-content-box-item-value {
font-size: 28rpx;
font-weight: 600;
color: #1890FF;
}
}
}
}
.member-consumption {
background: #fff;
border-radius: 16rpx;
padding: 24rpx;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
margin-bottom: 24rpx;
.member-consumption-item {
display: flex;
align-items: center;
margin-bottom: 18rpx;
&:last-child {
margin-bottom: 0;
}
.member-consumption-label {
font-size: 24rpx;
color: @text-primary;
width: 190rpx;
}
.member-consumption-progress {
flex: 1;
height: 24rpx;
background: linear-gradient(90deg, #1890ff 0%, #46B8F3 100%);
border-radius: 22rpx;
margin: 0 24rpx;
}
.member-consumption-progress2 {
flex: 1;
height: 24rpx;
background: linear-gradient(90deg, #52C41A 0%, #3CD495 100%);
border-radius: 22rpx;
margin: 0 24rpx;
}
.member-consumption-value {
font-size: 24rpx;
font-weight: 600;
color: @text-primary;
width: 190rpx;
text-align: right;
}
}
}
.member-overview {
display: flex;
width: 100%;
justify-content: space-between;
align-items: center;
.member-overview-item {
width: calc(25% - 18rpx);
box-sizing: border-box;
background: #fff;
border-radius: 16rpx;
padding: 12rpx;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
text-align: center;
.member-overview-item-top {
font-size: 28rpx;
font-weight: 600;
color: #1890FF;
margin-bottom: 8rpx;
}
.member-overview-item-bottom {
font-size: 24rpx;
color: @text-primary;
}
}
}
}
</style>