consumer模块完成90%,前端完成supabase对接
This commit is contained in:
145
mall/services/analytics/dashboardService.uts
Normal file
145
mall/services/analytics/dashboardService.uts
Normal file
@@ -0,0 +1,145 @@
|
||||
import { computeDateRange, toDateOnly } from './dateRange.uts'
|
||||
import { rpcOrEmptyArray, rpcOrNull, rpcOrValue } 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, range?: { start: string; end: string } | null): Promise<TrendData> {
|
||||
let startIso: string;
|
||||
let endIso: string;
|
||||
|
||||
if (range != null && range.start && range.end) {
|
||||
startIso = range.start;
|
||||
endIso = range.end;
|
||||
} else {
|
||||
const computedRange = computeDateRange(period)
|
||||
startIso = computedRange.startIso
|
||||
endIso = computedRange.endIso
|
||||
}
|
||||
|
||||
const p_start_date = toDateOnly(startIso)
|
||||
const p_end_date = toDateOnly(endIso)
|
||||
|
||||
const rows = await rpcOrEmptyArray('rpc_analytics_sales_trend', {
|
||||
p_start_date,
|
||||
p_end_date
|
||||
} 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.getAny?.('date') ?? ''}`
|
||||
x.push(d.length >= 10 ? d.slice(5) : d)
|
||||
gmv.push(safeNumber(row.getAny?.('gmv') ?? 0))
|
||||
orders.push(safeNumber(row.getAny?.('orders') ?? 0))
|
||||
}
|
||||
return { x, gmv, orders }
|
||||
}
|
||||
|
||||
export async function fetchDashboardRealtime(): Promise<any> {
|
||||
const [kpiRow, onlineUsersVal] = await Promise.all([
|
||||
rpcOrNull('rpc_analytics_realtime_kpis', {} as any),
|
||||
rpcOrValue('rpc_analytics_online_users', {} as any)
|
||||
])
|
||||
|
||||
const obj: any = kpiRow != null ? kpiRow : ({} as any)
|
||||
|
||||
return {
|
||||
gmv: Math.round(safeNumber(obj.getAny?.('gmv') ?? 0)),
|
||||
gmv_growth: safeNumber(obj.getAny?.('gmv_growth') ?? 0),
|
||||
orders: Math.round(safeNumber(obj.getAny?.('orders') ?? 0)),
|
||||
order_growth: safeNumber(obj.getAny?.('order_growth') ?? 0),
|
||||
online_users: Math.round(safeNumber(onlineUsersVal ?? 0)),
|
||||
conversion_rate: safeNumber(obj.getAny?.('conversion_rate') ?? 0),
|
||||
conversion_growth: safeNumber(obj.getAny?.('conversion_growth') ?? 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
|
||||
} 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') ?? 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') ?? 0),
|
||||
growth: safeNumber(row.getAny?.('growth') ?? 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
|
||||
}
|
||||
Reference in New Issue
Block a user