Files
akmon/pages/mall/analytics/index.uvue
2026-01-20 08:04:15 +08:00

1148 lines
24 KiB
Plaintext

<!-- 数据分析端首页 - UTS Android 兼容 -->
<template>
<view class="analytics-container">
<!-- 头部控制面板 -->
<view class="header">
<view class="header-left">
<text class="app-title">数据分析中心</text>
<text class="last-update">最后更新: {{ lastUpdateTime }}</text>
</view>
<view class="header-right">
<text class="refresh-btn" @click="refreshData">🔄</text>
<text class="export-btn" @click="exportReport">📊</text>
</view>
</view>
<!-- 核心指标实时大屏 -->
<view class="dashboard-section">
<text class="section-title">实时大屏</text>
<view class="dashboard-grid">
<view class="dashboard-card revenue">
<text class="card-title">实时GMV</text>
<text class="card-value">¥{{ formatNumber(realTimeMetrics.gmv) }}</text>
<text class="card-change positive">+{{ realTimeMetrics.gmv_growth }}%</text>
<text class="card-subtitle">较昨日同时段</text>
</view>
<view class="dashboard-card orders">
<text class="card-title">实时订单</text>
<text class="card-value">{{ formatNumber(realTimeMetrics.orders) }}</text>
<text class="card-change positive">+{{ realTimeMetrics.order_growth }}%</text>
<text class="card-subtitle">今日累计</text>
</view>
<view class="dashboard-card users">
<text class="card-title">在线用户</text>
<text class="card-value">{{ formatNumber(realTimeMetrics.online_users) }}</text>
<text class="card-change">实时数据</text>
<text class="card-subtitle">当前在线</text>
</view>
<view class="dashboard-card conversion">
<text class="card-title">转化率</text>
<text class="card-value">{{ realTimeMetrics.conversion_rate }}%</text>
<text class="card-change positive">+{{ realTimeMetrics.conversion_growth }}%</text>
<text class="card-subtitle">今日平均</text>
</view>
</view>
</view>
<!-- 时间维度选择 -->
<view class="time-filter-section">
<view class="filter-tabs">
<text v-for="period in timePeriods" :key="period.value"
class="filter-tab"
:class="{ active: selectedPeriod === period.value }"
@click="selectTimePeriod(period.value)">{{ period.label }}</text>
</view>
</view>
<!-- 销售分析 -->
<view class="sales-analysis-section">
<text class="section-title">销售分析</text>
<view class="analysis-cards">
<view class="analysis-card">
<text class="analysis-title">销售趋势</text>
<view class="trend-chart">
<!-- 这里应该是图表组件,暂用文字模拟 -->
<text class="chart-placeholder">📈 销售趋势图</text>
<text class="chart-description">{{ selectedPeriodText }}销售呈上升趋势</text>
</view>
<view class="trend-stats">
<view class="stat-item">
<text class="stat-label">总销售额</text>
<text class="stat-value">¥{{ formatNumber(salesAnalysis.total_sales) }}</text>
</view>
<view class="stat-item">
<text class="stat-label">平均客单价</text>
<text class="stat-value">¥{{ salesAnalysis.avg_order_value }}</text>
</view>
</view>
</view>
<view class="analysis-card">
<text class="analysis-title">商品分析</text>
<view class="product-chart">
<text class="chart-placeholder">📊 商品销量排行</text>
<view class="top-products">
<view v-for="product in topProducts" :key="product.id" class="product-rank-item">
<text class="rank-number">{{ product.rank }}</text>
<text class="product-name">{{ product.name }}</text>
<text class="product-sales">{{ product.sales }}件</text>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 用户行为分析 -->
<view class="user-behavior-section">
<text class="section-title">用户行为分析</text>
<view class="behavior-grid">
<view class="behavior-card">
<text class="behavior-title">用户活跃度</text>
<view class="behavior-metrics">
<view class="metric-row">
<text class="metric-label">日活用户</text>
<text class="metric-value">{{ formatNumber(userBehavior.daily_active) }}</text>
</view>
<view class="metric-row">
<text class="metric-label">月活用户</text>
<text class="metric-value">{{ formatNumber(userBehavior.monthly_active) }}</text>
</view>
<view class="metric-row">
<text class="metric-label">用户留存率</text>
<text class="metric-value">{{ userBehavior.retention_rate }}%</text>
</view>
</view>
</view>
<view class="behavior-card">
<text class="behavior-title">流量来源</text>
<view class="traffic-sources">
<view v-for="source in trafficSources" :key="source.name" class="source-item">
<text class="source-name">{{ source.name }}</text>
<view class="source-progress">
<view class="progress-bar" :style="{ width: source.percentage + '%' }"></view>
</view>
<text class="source-percentage">{{ source.percentage }}%</text>
</view>
</view>
</view>
</view>
</view>
<!-- 商家表现分析 -->
<view class="merchant-performance-section">
<text class="section-title">商家表现</text>
<view class="performance-header">
<text class="performance-subtitle">{{ selectedPeriodText }}商家排行榜</text>
<text class="view-all" @click="goToMerchantRanking">查看完整排行</text>
</view>
<view class="merchant-ranking">
<view v-for="merchant in topMerchants" :key="merchant.id" class="merchant-rank-item">
<view class="rank-info">
<text class="rank-badge" :class="getRankClass(merchant.rank)">{{ merchant.rank }}</text>
<image :src="merchant.logo || '/static/default-shop.png'" class="merchant-logo" mode="aspectFit" />
<view class="merchant-details">
<text class="merchant-name">{{ merchant.name }}</text>
<text class="merchant-category">{{ merchant.category }}</text>
</view>
</view>
<view class="performance-data">
<text class="sales-amount">¥{{ formatNumber(merchant.sales) }}</text>
<text class="growth-rate" :class="getGrowthClass(merchant.growth)">{{ merchant.growth > 0 ? '+' : '' }}{{ merchant.growth }}%</text>
</view>
</view>
</view>
</view>
<!-- 配送效率分析 -->
<view class="delivery-analysis-section">
<text class="section-title">配送效率</text>
<view class="delivery-metrics">
<view class="delivery-card">
<text class="delivery-title">配送时效</text>
<view class="delivery-stats">
<view class="stat-circle">
<text class="circle-value">{{ deliveryAnalysis.avg_delivery_time }}</text>
<text class="circle-unit">分钟</text>
<text class="circle-label">平均配送时间</text>
</view>
</view>
</view>
<view class="delivery-card">
<text class="delivery-title">配送覆盖</text>
<view class="coverage-info">
<text class="coverage-item">活跃配送员: {{ deliveryAnalysis.active_drivers }}人</text>
<text class="coverage-item">覆盖区域: {{ deliveryAnalysis.coverage_areas }}个</text>
<text class="coverage-item">准时率: {{ deliveryAnalysis.on_time_rate }}%</text>
</view>
</view>
</view>
</view>
<!-- 快速分析工具 -->
<view class="quick-tools-section">
<text class="section-title">快速分析</text>
<view class="tools-grid">
<view class="tool-card" @click="goToSalesReport">
<text class="tool-icon">📈</text>
<text class="tool-name">销售报表</text>
<text class="tool-description">详细销售数据分析</text>
</view>
<view class="tool-card" @click="goToUserAnalysis">
<text class="tool-icon">👥</text>
<text class="tool-name">用户分析</text>
<text class="tool-description">用户行为深度分析</text>
</view>
<view class="tool-card" @click="goToProductInsights">
<text class="tool-icon">📦</text>
<text class="tool-name">商品洞察</text>
<text class="tool-description">商品表现分析</text>
</view>
<view class="tool-card" @click="goToMarketTrends">
<text class="tool-icon">📊</text>
<text class="tool-name">市场趋势</text>
<text class="tool-description">行业趋势分析</text>
</view>
<view class="tool-card" @click="goToCustomReport">
<text class="tool-icon">🔧</text>
<text class="tool-name">自定义报表</text>
<text class="tool-description">创建专属分析报表</text>
</view>
<view class="tool-card" @click="goToAlerts">
<text class="tool-icon">⚠️</text>
<text class="tool-name">预警中心</text>
<text class="tool-description">异常数据预警</text>
</view>
</view>
</view>
</view>
</template>
<script lang="uts">
type TimePeriodType = {
value: string
label: string
}
type RealTimeMetricsType = {
gmv: number
gmv_growth: number
orders: number
order_growth: number
online_users: number
conversion_rate: number
conversion_growth: number
}
type SalesAnalysisType = {
total_sales: number
avg_order_value: number
}
type ProductRankType = {
id: string
rank: number
name: string
sales: number
}
type UserBehaviorType = {
daily_active: number
monthly_active: number
retention_rate: number
}
type TrafficSourceType = {
name: string
percentage: number
}
type MerchantRankType = {
id: string
rank: number
name: string
category: string
logo: string | null
sales: number
growth: number
}
type DeliveryAnalysisType = {
avg_delivery_time: number
active_drivers: number
coverage_areas: number
on_time_rate: number
}
export default {
data() {
return {
lastUpdateTime: '',
selectedPeriod: 'today',
timePeriods: [
{ value: 'today', label: '今日' },
{ value: 'week', label: '本周' },
{ value: 'month', label: '本月' },
{ value: 'quarter', label: '本季度' }
] as Array<TimePeriodType>,
realTimeMetrics: {
gmv: 0,
gmv_growth: 0,
orders: 0,
order_growth: 0,
online_users: 0,
conversion_rate: 0,
conversion_growth: 0
} as RealTimeMetricsType,
salesAnalysis: {
total_sales: 0,
avg_order_value: 0
} as SalesAnalysisType,
topProducts: [] as Array<ProductRankType>,
userBehavior: {
daily_active: 0,
monthly_active: 0,
retention_rate: 0
} as UserBehaviorType,
trafficSources: [] as Array<TrafficSourceType>,
topMerchants: [] as Array<MerchantRankType>,
deliveryAnalysis: {
avg_delivery_time: 0,
active_drivers: 0,
coverage_areas: 0,
on_time_rate: 0
} as DeliveryAnalysisType
}
},
computed: {
selectedPeriodText(): string {
const period = this.timePeriods.find(p => p.value === this.selectedPeriod)
return period ? period.label : '今日'
}
},
onLoad() {
this.loadAllData()
this.updateLastUpdateTime()
},
onShow() {
this.refreshRealTimeData()
},
methods: {
// 加载所有数据
loadAllData() {
this.loadRealTimeMetrics()
this.loadSalesAnalysis()
this.loadTopProducts()
this.loadUserBehavior()
this.loadTrafficSources()
this.loadTopMerchants()
this.loadDeliveryAnalysis()
},
// 加载实时指标
loadRealTimeMetrics() {
// TODO: 调用API获取实时数据
this.realTimeMetrics = {
gmv: 2580000,
gmv_growth: 15.6,
orders: 12580,
order_growth: 12.3,
online_users: 3456,
conversion_rate: 3.8,
conversion_growth: 0.5
}
},
// 加载销售分析
loadSalesAnalysis() {
// TODO: 调用API获取销售分析数据
this.salesAnalysis = {
total_sales: 1580000,
avg_order_value: 125.80
}
},
// 加载热销商品
loadTopProducts() {
// TODO: 调用API获取商品排行
this.topProducts = [
{ id: '1', rank: 1, name: '苹果iPhone 15', sales: 580 },
{ id: '2', rank: 2, name: '华为Mate 60', sales: 456 },
{ id: '3', rank: 3, name: '小米14 Pro', sales: 389 }
]
},
// 加载用户行为数据
loadUserBehavior() {
// TODO: 调用API获取用户行为数据
this.userBehavior = {
daily_active: 45600,
monthly_active: 280000,
retention_rate: 68.5
}
},
// 加载流量来源
loadTrafficSources() {
// TODO: 调用API获取流量来源数据
this.trafficSources = [
{ name: '直接访问', percentage: 45 },
{ name: '搜索引擎', percentage: 28 },
{ name: '社交媒体', percentage: 18 },
{ name: '广告推广', percentage: 9 }
]
},
// 加载商家排行
loadTopMerchants() {
// TODO: 调用API获取商家排行数据
this.topMerchants = [
{
id: '1',
rank: 1,
name: '华强北电子城',
category: '数码电子',
logo: '/static/merchant1.jpg',
sales: 580000,
growth: 15.6
},
{
id: '2',
rank: 2,
name: '时尚服装馆',
category: '服装鞋包',
logo: '/static/merchant2.jpg',
sales: 456000,
growth: 12.3
},
{
id: '3',
rank: 3,
name: '美食天地',
category: '食品生鲜',
logo: '/static/merchant3.jpg',
sales: 389000,
growth: -2.1
}
]
},
// 加载配送分析
loadDeliveryAnalysis() {
// TODO: 调用API获取配送分析数据
this.deliveryAnalysis = {
avg_delivery_time: 35,
active_drivers: 156,
coverage_areas: 25,
on_time_rate: 95.6
}
},
// 刷新实时数据
refreshRealTimeData() {
this.loadRealTimeMetrics()
this.updateLastUpdateTime()
},
// 刷新所有数据
refreshData() {
this.loadAllData()
this.updateLastUpdateTime()
uni.showToast({
title: '数据已刷新',
icon: 'success'
})
},
// 更新最后更新时间
updateLastUpdateTime() {
const now = new Date()
this.lastUpdateTime = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`
},
// 选择时间周期
selectTimePeriod(period: string) {
this.selectedPeriod = period
this.loadAllData()
},
// 格式化数字
formatNumber(num: number): string {
if (num >= 10000) {
return (num / 10000).toFixed(1) + '万'
}
return num.toString()
},
// 获取排名样式
getRankClass(rank: number): string {
switch (rank) {
case 1: return 'rank-gold'
case 2: return 'rank-silver'
case 3: return 'rank-bronze'
default: return 'rank-default'
}
},
// 获取增长率样式
getGrowthClass(growth: number): string {
if (growth > 0) return 'growth-positive'
if (growth < 0) return 'growth-negative'
return 'growth-neutral'
},
// 导出报表
exportReport() {
uni.showToast({
title: '正在导出报表',
icon: 'loading'
})
// TODO: 实现报表导出功能
},
// 导航方法
goToMerchantRanking() {
uni.navigateTo({
url: '/pages/mall/analytics/merchant-ranking'
})
},
goToSalesReport() {
uni.navigateTo({
url: '/pages/mall/analytics/sales-report'
})
},
goToUserAnalysis() {
uni.navigateTo({
url: '/pages/mall/analytics/user-analysis'
})
},
goToProductInsights() {
uni.navigateTo({
url: '/pages/mall/analytics/product-insights'
})
},
goToMarketTrends() {
uni.navigateTo({
url: '/pages/mall/analytics/market-trends'
})
},
goToCustomReport() {
uni.navigateTo({
url: '/pages/mall/analytics/custom-report'
})
},
goToAlerts() {
uni.navigateTo({
url: '/pages/mall/analytics/alerts'
})
}
}
}
</script>
<style>
.analytics-container {
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 40rpx;
}
.header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 40rpx 30rpx 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
display: flex;
flex-direction: column;
}
.app-title {
font-size: 36rpx;
font-weight: bold;
color: #fff;
margin-bottom: 8rpx;
}
.last-update {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.8);
}
.header-right {
display: flex;
align-items: center;
}
.refresh-btn,
.export-btn {
font-size: 32rpx;
color: #fff;
margin-left: 30rpx;
}
.dashboard-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.section-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
.dashboard-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.dashboard-card {
width: 48%;
padding: 30rpx 20rpx;
border-radius: 12rpx;
margin-bottom: 20rpx;
position: relative;
}
.revenue {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.orders {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.users {
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
}
.conversion {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
}
.card-title {
font-size: 24rpx;
color: rgba(255, 255, 255, 0.9);
margin-bottom: 15rpx;
}
.card-value {
font-size: 36rpx;
font-weight: bold;
color: #fff;
margin-bottom: 10rpx;
}
.card-change {
font-size: 20rpx;
color: rgba(255, 255, 255, 0.8);
margin-bottom: 8rpx;
}
.positive {
color: #4CAF50;
background-color: rgba(255, 255, 255, 0.2);
padding: 4rpx 8rpx;
border-radius: 8rpx;
}
.card-subtitle {
font-size: 18rpx;
color: rgba(255, 255, 255, 0.7);
}
.time-filter-section {
margin: 20rpx;
}
.filter-tabs {
display: flex;
background-color: #fff;
border-radius: 12rpx;
padding: 8rpx;
}
.filter-tab {
flex: 1;
text-align: center;
padding: 15rpx;
font-size: 26rpx;
color: #666;
border-radius: 8rpx;
}
.filter-tab.active {
background-color: #667eea;
color: #fff;
}
.sales-analysis-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.analysis-cards {
display: flex;
flex-direction: column;
}
.analysis-card {
border: 1rpx solid #e5e5e5;
border-radius: 12rpx;
padding: 25rpx;
margin-bottom: 20rpx;
}
.analysis-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.trend-chart,
.product-chart {
text-align: center;
margin-bottom: 20rpx;
}
.chart-placeholder {
font-size: 48rpx;
margin-bottom: 15rpx;
}
.chart-description {
font-size: 24rpx;
color: #666;
}
.trend-stats {
display: flex;
justify-content: space-around;
}
.stat-item {
display: flex;
flex-direction: column;
align-items: center;
}
.stat-label {
font-size: 22rpx;
color: #666;
margin-bottom: 8rpx;
}
.stat-value {
font-size: 28rpx;
font-weight: bold;
color: #667eea;
}
.top-products {
display: flex;
flex-direction: column;
}
.product-rank-item {
display: flex;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.product-rank-item:last-child {
border-bottom: none;
}
.rank-number {
width: 60rpx;
height: 60rpx;
background-color: #667eea;
color: #fff;
border-radius: 30rpx;
text-align: center;
line-height: 60rpx;
font-size: 24rpx;
margin-right: 20rpx;
}
.product-name {
flex: 1;
font-size: 26rpx;
color: #333;
}
.product-sales {
font-size: 24rpx;
color: #666;
}
.user-behavior-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.behavior-grid {
display: flex;
flex-direction: column;
}
.behavior-card {
border: 1rpx solid #e5e5e5;
border-radius: 12rpx;
padding: 25rpx;
margin-bottom: 20rpx;
}
.behavior-title {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.behavior-metrics {
display: flex;
flex-direction: column;
}
.metric-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.metric-row:last-child {
border-bottom: none;
}
.metric-label {
font-size: 26rpx;
color: #666;
}
.metric-value {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.traffic-sources {
display: flex;
flex-direction: column;
}
.source-item {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.source-name {
width: 150rpx;
font-size: 24rpx;
color: #333;
}
.source-progress {
flex: 1;
height: 20rpx;
background-color: #f0f0f0;
border-radius: 10rpx;
margin: 0 20rpx;
position: relative;
}
.progress-bar {
height: 100%;
background-color: #667eea;
border-radius: 10rpx;
}
.source-percentage {
width: 80rpx;
text-align: right;
font-size: 24rpx;
color: #666;
}
.merchant-performance-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.performance-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.performance-subtitle {
font-size: 26rpx;
color: #666;
}
.view-all {
font-size: 24rpx;
color: #667eea;
}
.merchant-ranking {
display: flex;
flex-direction: column;
}
.merchant-rank-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f0f0f0;
}
.merchant-rank-item:last-child {
border-bottom: none;
}
.rank-info {
display: flex;
align-items: center;
flex: 1;
}
.rank-badge {
width: 50rpx;
height: 50rpx;
border-radius: 25rpx;
text-align: center;
line-height: 50rpx;
font-size: 20rpx;
font-weight: bold;
margin-right: 20rpx;
}
.rank-gold {
background-color: #FFD700;
color: #fff;
}
.rank-silver {
background-color: #C0C0C0;
color: #fff;
}
.rank-bronze {
background-color: #CD7F32;
color: #fff;
}
.rank-default {
background-color: #f0f0f0;
color: #666;
}
.merchant-logo {
width: 60rpx;
height: 60rpx;
border-radius: 30rpx;
margin-right: 15rpx;
}
.merchant-details {
display: flex;
flex-direction: column;
}
.merchant-name {
font-size: 26rpx;
color: #333;
margin-bottom: 5rpx;
}
.merchant-category {
font-size: 22rpx;
color: #666;
}
.performance-data {
display: flex;
flex-direction: column;
align-items: flex-end;
}
.sales-amount {
font-size: 28rpx;
font-weight: bold;
color: #333;
margin-bottom: 5rpx;
}
.growth-rate {
font-size: 22rpx;
}
.growth-positive {
color: #4CAF50;
}
.growth-negative {
color: #F44336;
}
.growth-neutral {
color: #666;
}
.delivery-analysis-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.delivery-metrics {
display: flex;
justify-content: space-between;
}
.delivery-card {
width: 48%;
border: 1rpx solid #e5e5e5;
border-radius: 12rpx;
padding: 25rpx;
text-align: center;
}
.delivery-title {
font-size: 26rpx;
font-weight: bold;
color: #333;
margin-bottom: 20rpx;
}
.delivery-stats {
display: flex;
justify-content: center;
}
.stat-circle {
display: flex;
flex-direction: column;
align-items: center;
}
.circle-value {
font-size: 48rpx;
font-weight: bold;
color: #667eea;
}
.circle-unit {
font-size: 20rpx;
color: #666;
margin-bottom: 10rpx;
}
.circle-label {
font-size: 22rpx;
color: #333;
}
.coverage-info {
display: flex;
flex-direction: column;
}
.coverage-item {
font-size: 24rpx;
color: #333;
margin-bottom: 10rpx;
text-align: left;
}
.quick-tools-section {
background-color: #fff;
margin: 20rpx;
padding: 30rpx;
border-radius: 16rpx;
}
.tools-grid {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.tool-card {
width: 30%;
border: 1rpx solid #e5e5e5;
border-radius: 12rpx;
padding: 25rpx 15rpx;
margin-bottom: 20rpx;
text-align: center;
}
.tool-icon {
font-size: 48rpx;
margin-bottom: 15rpx;
}
.tool-name {
font-size: 24rpx;
font-weight: bold;
color: #333;
margin-bottom: 8rpx;
}
.tool-description {
font-size: 20rpx;
color: #666;
}
</style>