接入数据库
This commit is contained in:
@@ -209,9 +209,116 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
calcDateRange() {
|
||||
const now = new Date()
|
||||
const endDate = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
||||
const days = this.selectedPeriod === '7d' ? 7 : this.selectedPeriod === '30d' ? 30 : this.selectedPeriod === '90d' ? 90 : 365
|
||||
const startDate = new Date(endDate.getTime() - (days - 1) * 24 * 60 * 60 * 1000)
|
||||
return { startDate, endDate, days }
|
||||
},
|
||||
|
||||
async loadSalesData() {
|
||||
// TODO: 实现销售数据加载
|
||||
this.updateTime()
|
||||
try {
|
||||
this.updateTime()
|
||||
const now = new Date()
|
||||
const { startDate, endDate, days } = this.calcDateRange()
|
||||
|
||||
// 1) KPI:复用 realtime_kpis 的口径(GMV/订单/转化率),把窗口替换成“周期范围 vs 上一周期”
|
||||
const periodStart = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate())
|
||||
const periodEnd = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate() + 1) // 包含 endDate 当天
|
||||
const prevStart = new Date(periodStart.getTime() - days * 24 * 60 * 60 * 1000)
|
||||
const prevEnd = new Date(periodStart.getTime())
|
||||
|
||||
const pKpi = new UTSJSONObject()
|
||||
pKpi.set('p_start', periodStart.toISOString())
|
||||
pKpi.set('p_end', periodEnd.toISOString())
|
||||
pKpi.set('p_compare_start', prevStart.toISOString())
|
||||
pKpi.set('p_compare_end', prevEnd.toISOString())
|
||||
pKpi.set('p_merchant_id', null)
|
||||
|
||||
const kpiRes: any = await supa.rpc('rpc_analytics_realtime_kpis', pKpi)
|
||||
const row = Array.isArray(kpiRes.data) && kpiRes.data.length > 0 ? kpiRes.data[0] : (kpiRes.data || {})
|
||||
const safe = (v: any): number => {
|
||||
const n = Number(v)
|
||||
return isFinite(n) ? n : 0
|
||||
}
|
||||
const gmv = safe(row.gmv)
|
||||
const orders = safe(row.orders)
|
||||
const avgOrder = orders > 0 ? gmv / orders : 0
|
||||
this.salesData = {
|
||||
gmv: Math.round(gmv),
|
||||
gmv_growth: safe(row.gmv_growth),
|
||||
orders: Math.round(orders),
|
||||
order_growth: safe(row.order_growth),
|
||||
conversion_rate: safe(row.conversion_rate),
|
||||
conversion_growth: safe(row.conversion_growth),
|
||||
avg_order_amount: avgOrder,
|
||||
avg_order_growth: safe(row.gmv_growth) // 兜底:暂无独立口径,先跟随 GMV 增长
|
||||
}
|
||||
|
||||
// 2) 趋势(复用 trend_data)
|
||||
const pTrend = new UTSJSONObject()
|
||||
pTrend.set('p_start_date', startDate.toISOString().slice(0, 10))
|
||||
pTrend.set('p_end_date', endDate.toISOString().slice(0, 10))
|
||||
pTrend.set('p_merchant_id', null)
|
||||
const trendRes: any = await supa.rpc('rpc_analytics_trend_data', pTrend)
|
||||
const tRows: Array<any> = Array.isArray(trendRes.data) ? (trendRes.data as Array<any>) : []
|
||||
const x: Array<string> = []
|
||||
const gmvArr: Array<number> = []
|
||||
const orderArr: Array<number> = []
|
||||
for (let i = 0; i < tRows.length; i++) {
|
||||
const d = `${tRows[i].date}`
|
||||
x.push(d.slice(5))
|
||||
gmvArr.push(Number(tRows[i].gmv) || 0)
|
||||
orderArr.push(Number(tRows[i].orders) || 0)
|
||||
}
|
||||
this.trend = { x, gmv: gmvArr, orders: orderArr }
|
||||
|
||||
// 3) TOP 商品/商家
|
||||
const pTopP = new UTSJSONObject()
|
||||
pTopP.set('p_start_date', startDate.toISOString().slice(0, 10))
|
||||
pTopP.set('p_end_date', endDate.toISOString().slice(0, 10))
|
||||
pTopP.set('p_limit', 10)
|
||||
pTopP.set('p_merchant_id', null)
|
||||
const topPRes: any = await supa.rpc('rpc_analytics_top_products', pTopP)
|
||||
const pRows: Array<any> = Array.isArray(topPRes.data) ? (topPRes.data as Array<any>) : []
|
||||
const pList: Array<ProductRank> = []
|
||||
for (let i = 0; i < pRows.length; i++) {
|
||||
pList.push({ id: `${pRows[i].id}`, rank: i + 1, name: `${pRows[i].name}`, sales: Number(pRows[i].sales) || 0 })
|
||||
}
|
||||
this.topProducts = pList
|
||||
|
||||
const pTopM = new UTSJSONObject()
|
||||
pTopM.set('p_start_date', startDate.toISOString().slice(0, 10))
|
||||
pTopM.set('p_end_date', endDate.toISOString().slice(0, 10))
|
||||
pTopM.set('p_limit', 10)
|
||||
const topMRes: any = await supa.rpc('rpc_analytics_top_merchants', pTopM)
|
||||
const mRows: Array<any> = Array.isArray(topMRes.data) ? (topMRes.data as Array<any>) : []
|
||||
const mList: Array<MerchantRank> = []
|
||||
for (let i = 0; i < mRows.length; i++) {
|
||||
mList.push({
|
||||
id: `${mRows[i].id}`,
|
||||
rank: i + 1,
|
||||
name: `${mRows[i].name}`,
|
||||
sales: Number(mRows[i].sales) || 0,
|
||||
growth: Number(mRows[i].growth) || 0
|
||||
})
|
||||
}
|
||||
this.topMerchants = mList
|
||||
|
||||
// 4) 地域分布:当前基础表无“省份/城市”字段,这里用“商家 GMV 分布”做动态替代
|
||||
this.regionChartOption = {
|
||||
grid: { left: 40, right: 18, top: 20, bottom: 40 },
|
||||
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
|
||||
xAxis: { type: 'category', data: mList.map((m) => m.name), axisLabel: { rotate: 30, color: 'rgba(0,0,0,0.55)' } },
|
||||
yAxis: { type: 'value', axisLabel: { color: 'rgba(0,0,0,0.55)' }, splitLine: { lineStyle: { color: 'rgba(0,0,0,0.06)' } } },
|
||||
series: [{ type: 'bar', data: mList.map((m) => m.sales), barWidth: 18, itemStyle: { borderRadius: 6 } }]
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('loadSalesData failed', e)
|
||||
} finally {
|
||||
this.updateTime()
|
||||
}
|
||||
},
|
||||
|
||||
selectPeriod(p: string) {
|
||||
|
||||
Reference in New Issue
Block a user