接入数据库

This commit is contained in:
comlibmb
2026-01-26 21:34:17 +08:00
parent c14f67cfc8
commit 3fbd9a2b3d
26 changed files with 3559 additions and 427 deletions

View File

@@ -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) {