152 lines
5.8 KiB
Plaintext
152 lines
5.8 KiB
Plaintext
import { computeDateRange, toDateOnly } from './dateRange.uts'
|
|
import { rpcOrEmptyArray, rpcOrNull } from './rpc.uts'
|
|
|
|
export type TrendData = { x: Array<string>; gmv: Array<number>; orders: Array<number> }
|
|
export type SegmentItem = { name: string; value: number }
|
|
export type TrafficItem = { name: string; value: number }
|
|
export type TopProductItem = { id: string; rank: number; name: string; sales: number }
|
|
export type TopMerchantItem = { id: string; rank: number; name: string; sales: number; growth: number }
|
|
|
|
function safeNumber(v: any): number {
|
|
const n = Number(v)
|
|
return isFinite(n) ? n : 0
|
|
}
|
|
|
|
export async function fetchDashboardTrend(period: string): Promise<TrendData> {
|
|
const { startIso, endIso } = computeDateRange(period)
|
|
const p_start_date = toDateOnly(startIso)
|
|
const p_end_date = toDateOnly(endIso)
|
|
|
|
const rows = await rpcOrEmptyArray('rpc_analytics_trend_data', {
|
|
p_start_date,
|
|
p_end_date,
|
|
p_merchant_id: null
|
|
} as any)
|
|
|
|
const x: Array<string> = []
|
|
const gmv: Array<number> = []
|
|
const orders: Array<number> = []
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row: any = rows[i]
|
|
const d = `${row.getString?.('date') ?? row.getString?.('day') ?? row.getString?.('date_key') ?? ''}`
|
|
if (d && d.length >= 10) x.push(d.slice(5))
|
|
else x.push(`${i + 1}`)
|
|
gmv.push(safeNumber(row.getAny?.('gmv') ?? row.getAny?.('total_amount') ?? 0))
|
|
orders.push(safeNumber(row.getAny?.('orders') ?? row.getAny?.('order_count') ?? 0))
|
|
}
|
|
return { x, gmv, orders }
|
|
}
|
|
|
|
export async function fetchDashboardRealtime(): Promise<any> {
|
|
const now = new Date()
|
|
const today0 = new Date(now.getFullYear(), now.getMonth(), now.getDate())
|
|
const todayISO = today0.toISOString()
|
|
|
|
const ySame = new Date(now.getTime() - 24 * 60 * 60 * 1000)
|
|
const y0 = new Date(ySame.getFullYear(), ySame.getMonth(), ySame.getDate())
|
|
|
|
const row = await rpcOrNull('rpc_analytics_realtime_kpis', {
|
|
p_start: todayISO,
|
|
p_end: now.toISOString(),
|
|
p_compare_start: y0.toISOString(),
|
|
p_compare_end: ySame.toISOString(),
|
|
p_merchant_id: null
|
|
} as any)
|
|
|
|
const safe = (v: any): number => {
|
|
const n = Number(v)
|
|
return isFinite(n) ? n : 0
|
|
}
|
|
|
|
const obj: any = row != null ? row : ({} as any)
|
|
return {
|
|
gmv: Math.round(safe(obj.getAny?.('gmv') ?? obj.getAny?.('total_gmv') ?? obj.getAny?.('revenue') ?? 0)),
|
|
gmv_growth: safe(obj.getAny?.('gmv_growth') ?? obj.getAny?.('gmv_growth_rate') ?? obj.getAny?.('revenue_growth') ?? 0),
|
|
orders: Math.round(safe(obj.getAny?.('orders') ?? obj.getAny?.('order_count') ?? obj.getAny?.('total_orders') ?? 0)),
|
|
order_growth: safe(obj.getAny?.('order_growth') ?? obj.getAny?.('order_growth_rate') ?? 0),
|
|
online_users: Math.round(safe(obj.getAny?.('online_users') ?? obj.getAny?.('active_users') ?? obj.getAny?.('current_users') ?? 0)),
|
|
conversion_rate: safe(obj.getAny?.('conversion_rate') ?? obj.getAny?.('conversion') ?? 0),
|
|
conversion_growth: safe(obj.getAny?.('conversion_growth') ?? obj.getAny?.('conversion_growth_rate') ?? 0)
|
|
}
|
|
}
|
|
|
|
export async function fetchDashboardTopProducts(period: string, limit: number = 50): Promise<Array<TopProductItem>> {
|
|
const { startIso, endIso } = computeDateRange(period)
|
|
const rows = await rpcOrEmptyArray('rpc_analytics_top_products', {
|
|
p_start_date: toDateOnly(startIso),
|
|
p_end_date: toDateOnly(endIso),
|
|
p_limit: limit,
|
|
p_merchant_id: null
|
|
} as any)
|
|
|
|
const list: Array<TopProductItem> = []
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row: any = rows[i]
|
|
list.push({
|
|
id: `${row.getAny?.('id') ?? i}`,
|
|
rank: i + 1,
|
|
name: `${row.getAny?.('name') ?? '未知商品'}`,
|
|
sales: safeNumber(row.getAny?.('sales') ?? row.getAny?.('total_amount') ?? 0)
|
|
})
|
|
}
|
|
return list
|
|
}
|
|
|
|
export async function fetchDashboardTopMerchants(period: string, limit: number = 50): Promise<Array<TopMerchantItem>> {
|
|
const { startIso, endIso } = computeDateRange(period)
|
|
const rows = await rpcOrEmptyArray('rpc_analytics_top_merchants', {
|
|
p_start_date: toDateOnly(startIso),
|
|
p_end_date: toDateOnly(endIso),
|
|
p_limit: limit
|
|
} as any)
|
|
|
|
const list: Array<TopMerchantItem> = []
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row: any = rows[i]
|
|
list.push({
|
|
id: `${row.getAny?.('id') ?? i}`,
|
|
rank: i + 1,
|
|
name: `${row.getAny?.('name') ?? row.getAny?.('shop_name') ?? '未知商家'}`,
|
|
sales: safeNumber(row.getAny?.('sales') ?? row.getAny?.('total_amount') ?? 0),
|
|
growth: safeNumber(row.getAny?.('growth') ?? row.getAny?.('growth_rate') ?? 0)
|
|
})
|
|
}
|
|
return list
|
|
}
|
|
|
|
export async function fetchDashboardUserSegments(period: string): Promise<Array<SegmentItem>> {
|
|
const { startIso, endIso } = computeDateRange(period)
|
|
const rows = await rpcOrEmptyArray('rpc_analytics_user_segments', {
|
|
p_start_date: toDateOnly(startIso),
|
|
p_end_date: toDateOnly(endIso)
|
|
} as any)
|
|
|
|
const list: Array<SegmentItem> = []
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row: any = rows[i]
|
|
list.push({
|
|
name: `${row.getAny?.('name') ?? row.getAny?.('segment_name') ?? row.getAny?.('label') ?? '未知'}`,
|
|
value: safeNumber(row.getAny?.('value') ?? row.getAny?.('count') ?? row.getAny?.('amount') ?? 0)
|
|
})
|
|
}
|
|
return list
|
|
}
|
|
|
|
export async function fetchDashboardTrafficSources(period: string): Promise<Array<TrafficItem>> {
|
|
const { startIso, endIso } = computeDateRange(period)
|
|
const rows = await rpcOrEmptyArray('rpc_analytics_traffic_sources', {
|
|
p_start_date: toDateOnly(startIso),
|
|
p_end_date: toDateOnly(endIso)
|
|
} as any)
|
|
|
|
const list: Array<TrafficItem> = []
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row: any = rows[i]
|
|
list.push({
|
|
name: `${row.getAny?.('name') ?? row.getAny?.('source_name') ?? row.getAny?.('label') ?? '未知'}`,
|
|
value: safeNumber(row.getAny?.('value') ?? row.getAny?.('count') ?? row.getAny?.('amount') ?? 0)
|
|
})
|
|
}
|
|
return list
|
|
}
|