import React, { useEffect, useState, useCallback } from 'react' import { View, Text, ScrollView } from '@tarojs/components' import NavBar from '@/components/NavBar' import { pageShopOrder } from '@/api/shop/shopOrder' import type { ShopOrder } from '@/api/shop/shopOrder/model' definePageConfig({ navigationBarTitleText: '销售统计', }) type TimeRange = 'week' | 'month' interface DayStat { date: string amount: number orders: number } const SalesStatisticsPage: React.FC = () => { const [timeRange, setTimeRange] = useState('week') const [loading, setLoading] = useState(true) const [dayStats, setDayStats] = useState([]) const [totalRevenue, setTotalRevenue] = useState(0) const [totalOrders, setTotalOrders] = useState(0) const [avgPrice, setAvgPrice] = useState(0) const formatDateKey = (date: Date) => { const m = String(date.getMonth() + 1).padStart(2, '0') const d = String(date.getDate()).padStart(2, '0') return `${m}-${d}` } const formatDateFull = (date: Date) => { const y = date.getFullYear() const m = String(date.getMonth() + 1).padStart(2, '0') const d = String(date.getDate()).padStart(2, '0') return `${y}-${m}-${d}` } const loadData = useCallback(async (range: TimeRange) => { setLoading(true) try { const now = new Date() const days = range === 'week' ? 7 : 30 const startDate = new Date(now.getTime() - (days - 1) * 24 * 60 * 60 * 1000) const startStr = `${formatDateFull(startDate)} 00:00:00` const endStr = `${formatDateFull(now)} 23:59:59` const res = await pageShopOrder({ page: 1, limit: 500, startTime: startStr, endTime: endStr, } as any).catch(() => null) if (!res?.list) { setDayStats([]) setTotalRevenue(0) setTotalOrders(0) setAvgPrice(0) return } const orders: ShopOrder[] = res.list // 按天分组 const dayMap: Record = {} for (let i = 0; i < days; i++) { const d = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1000) dayMap[formatDateKey(d)] = { amount: 0, orders: 0 } } let totalRev = 0 let paidCount = 0 orders.forEach(o => { if (!o.createTime) return const key = o.createTime.substring(5, 10) // MM-DD if (dayMap[key]) { const amt = parseFloat(o.payPrice || '0') if (o.payStatus) { dayMap[key].amount += amt totalRev += amt paidCount++ } dayMap[key].orders += 1 } }) const stats: DayStat[] = Object.entries(dayMap).map(([date, d]) => ({ date, amount: d.amount, orders: d.orders, })) setDayStats(stats) setTotalRevenue(totalRev) setTotalOrders(orders.length) setAvgPrice(paidCount > 0 ? totalRev / paidCount : 0) } catch (e) { console.error('加载销售数据失败', e) } finally { setLoading(false) } }, []) useEffect(() => { loadData(timeRange) }, [timeRange, loadData]) const maxAmount = Math.max(...dayStats.map(d => d.amount), 1) return ( {/* 时间范围选择 */} {([{ key: 'week', label: '近7天' }, { key: 'month', label: '近30天' }] as const).map(option => ( setTimeRange(option.key)} > {option.label} {timeRange === option.key && ( )} ))} {loading ? ( 加载中... ) : ( {/* 汇总数据 */} ¥{totalRevenue.toFixed(2)} 总销售额 {totalOrders} 总订单数 ¥{avgPrice.toFixed(2)} 客单价 {totalOrders > 0 ? ((dayStats.filter(d => d.amount > 0).length / dayStats.length) * 100).toFixed(1) : '0.0'}% 有销售天占比 {/* 销售趋势柱状图 */} 销售趋势 {dayStats.every(d => d.amount === 0) ? ( 暂无销售数据 ) : ( {dayStats.map((item, index) => ( 0 ? 4 : 0)}%`, backgroundColor: item.amount > 0 ? '#ef4444' : '#e5e7eb', minHeight: item.amount > 0 ? '4px' : '2px', }} /> ))} {dayStats.map((item, index) => ( {item.date.substring(3)} ))} )} {/* 每日明细 */} 每日明细 {dayStats.length === 0 ? ( 暂无数据 ) : ( dayStats.slice().reverse().map((item, index) => ( {item.date} ¥{item.amount.toFixed(2)} {item.orders} 单 )) )} )} ) } export default SalesStatisticsPage