208 lines
4.2 KiB
Plaintext
208 lines
4.2 KiB
Plaintext
<template>
|
|
<view class="chart-container">
|
|
<view class="chart-header">
|
|
<view class="header-left">
|
|
<view class="title-icon">
|
|
<text class="iconfont">O</text>
|
|
</view>
|
|
<text class="chart-title">购买用户分析</text>
|
|
</view>
|
|
</view>
|
|
|
|
<view class="chart-body">
|
|
<view class="chart-view-wrapper">
|
|
<EChartsView
|
|
v-if="!loading && chartOption"
|
|
:option="chartOption"
|
|
class="echarts-view"
|
|
/>
|
|
|
|
<!-- Loading 状态 -->
|
|
<view v-if="loading" class="loading-state">
|
|
<text class="loading-text">计算中...</text>
|
|
</view>
|
|
|
|
<!-- 空数据状态 -->
|
|
<view v-if="!loading && chartData.length === 0" class="empty-state">
|
|
<text class="empty-text">无相关消费记录</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
|
import { PurchaseUserStat } from '@/types/charts.uts'
|
|
|
|
/**
|
|
* PurchaseUserPie 购买用户统计饼图
|
|
* 展示不同消费特征的用户分布情况
|
|
*/
|
|
|
|
// --- 状态定义 ---
|
|
const loading = ref(false)
|
|
const chartData = ref<PurchaseUserStat[]>([])
|
|
|
|
// --- ECharts 配置计算属性 ---
|
|
const chartOption = computed(() : any => {
|
|
if (chartData.value.length === 0) return null
|
|
|
|
return {
|
|
tooltip: {
|
|
trigger: 'item',
|
|
formatter: '{b}: {c} ({d}%)'
|
|
},
|
|
legend: {
|
|
bottom: '5%',
|
|
left: 'center',
|
|
itemWidth: 10,
|
|
itemHeight: 10,
|
|
textStyle: {
|
|
fontSize: 12,
|
|
color: '#666'
|
|
}
|
|
},
|
|
// 视觉色彩方案
|
|
color: ['#1890ff', '#36cfc9', '#ffc53d', '#ff4d4f'],
|
|
series: [
|
|
{
|
|
name: '用户分布',
|
|
type: 'pie',
|
|
radius: ['45%', '70%'], // 采用环形图设计,更具现代感
|
|
avoidLabelOverlap: true,
|
|
itemStyle: {
|
|
borderRadius: 6,
|
|
borderColor: '#fff',
|
|
borderWidth: 2
|
|
},
|
|
label: {
|
|
show: true,
|
|
position: 'outside',
|
|
formatter: '{b}\n{d}%',
|
|
fontSize: 11,
|
|
color: '#888'
|
|
},
|
|
emphasis: {
|
|
scale: true,
|
|
itemStyle: {
|
|
shadowBlur: 10,
|
|
shadowOffsetX: 0,
|
|
shadowColor: 'rgba(0, 0, 0, 0.1)'
|
|
}
|
|
},
|
|
labelLine: {
|
|
show: true,
|
|
length: 12,
|
|
length2: 10,
|
|
smooth: true
|
|
},
|
|
data: chartData.value.map(item => {
|
|
return {
|
|
name: item.label,
|
|
value: item.value
|
|
}
|
|
})
|
|
}
|
|
]
|
|
}
|
|
})
|
|
|
|
// --- 数据获取逻辑 ---
|
|
|
|
/**
|
|
* 模拟获取统计数据
|
|
*/
|
|
const fetchData = () => {
|
|
loading.value = true
|
|
|
|
setTimeout(() => {
|
|
chartData.value = [
|
|
{ label: '未消费用户', value: 342 } as PurchaseUserStat,
|
|
{ label: '消费一次', value: 156 } as PurchaseUserStat,
|
|
{ label: '留存客户', value: 218 } as PurchaseUserStat,
|
|
{ label: '回流客户', value: 84 } as PurchaseUserStat
|
|
]
|
|
loading.value = false
|
|
}, 1000)
|
|
}
|
|
|
|
// 暴露方法
|
|
defineExpose({
|
|
refresh: fetchData
|
|
})
|
|
|
|
onMounted(() => {
|
|
fetchData()
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.chart-container {
|
|
background: #ffffff;
|
|
border-radius: 4px;
|
|
border: 1px solid #f0f0f0;
|
|
padding: 16px;
|
|
}
|
|
|
|
.chart-header {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.header-left {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 8px;
|
|
}
|
|
|
|
.title-icon {
|
|
width: 24px;
|
|
height: 24px;
|
|
background: #fff7e6;
|
|
border-radius: 4px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.chart-title {
|
|
font-size: 15px;
|
|
font-weight: 500;
|
|
color: #333;
|
|
}
|
|
|
|
.chart-body {
|
|
position: relative;
|
|
}
|
|
|
|
.chart-view-wrapper {
|
|
width: 100%;
|
|
height: 320px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.echarts-view {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.loading-state, .empty-state {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.loading-text, .empty-text {
|
|
color: #999;
|
|
font-size: 14px;
|
|
}
|
|
</style>
|