数据分析ui补充完善,接入数据库
This commit is contained in:
@@ -94,7 +94,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="uts">
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
import supa, { ensureSupabaseReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import AnalyticsSidebarMenu from '@/components/analytics/AnalyticsSidebarMenu.uvue'
|
||||
import AnalyticsTopBar from '@/components/analytics/AnalyticsTopBar.uvue'
|
||||
import EChartsView from '@/uni_modules/charts/EChartsView.vue'
|
||||
@@ -148,9 +148,108 @@ export default {
|
||||
|
||||
methods: {
|
||||
async loadMarketData() {
|
||||
// TODO: 实现市场数据加载
|
||||
this.updateTime()
|
||||
this.buildChartOptions()
|
||||
try {
|
||||
const now = new Date()
|
||||
const start = new Date(now.getTime())
|
||||
if (this.selectedPeriod === '7d') start.setDate(start.getDate() - 7)
|
||||
else if (this.selectedPeriod === '30d') start.setDate(start.getDate() - 30)
|
||||
else if (this.selectedPeriod === '90d') start.setDate(start.getDate() - 90)
|
||||
else if (this.selectedPeriod === '1y') start.setFullYear(start.getFullYear() - 1)
|
||||
const startIso = start.toISOString()
|
||||
const endIso = now.toISOString()
|
||||
|
||||
await ensureSupabaseReady()
|
||||
|
||||
// 1) 市场整体趋势(按天 GMV / 订单 / 用户)
|
||||
let trendRows: Array<UTSJSONObject> = []
|
||||
let categoryRows: Array<UTSJSONObject> = []
|
||||
let seasonalRows: Array<UTSJSONObject> = []
|
||||
let priceRows: Array<UTSJSONObject> = []
|
||||
let competitionRows: Array<UTSJSONObject> = []
|
||||
|
||||
const marketRes = await supa.rpc('rpc_analytics_market_trend_daily', {
|
||||
p_start: startIso,
|
||||
p_end: endIso
|
||||
})
|
||||
if (marketRes.status === 404) {
|
||||
console.warn('rpc_analytics_market_trend_daily not found, market trend will be empty')
|
||||
} else if (marketRes.error != null) {
|
||||
console.error('rpc_analytics_market_trend_daily error:', marketRes.error)
|
||||
} else {
|
||||
const anyData = marketRes.data as any
|
||||
trendRows = Array.isArray(anyData) ? anyData as Array<UTSJSONObject> : []
|
||||
}
|
||||
|
||||
// 2) 行业对比(按分类 GMV)
|
||||
const catRes = await supa.rpc('rpc_analytics_category_sales', {
|
||||
p_start_date: startIso.substring(0, 10),
|
||||
p_end_date: endIso.substring(0, 10)
|
||||
})
|
||||
if (catRes.status === 404) {
|
||||
console.warn('rpc_analytics_category_sales not found, industry comparison will be empty')
|
||||
} else if (catRes.error != null) {
|
||||
console.error('rpc_analytics_category_sales error:', catRes.error)
|
||||
} else {
|
||||
const cAny = catRes.data as any
|
||||
categoryRows = Array.isArray(cAny) ? cAny as Array<UTSJSONObject> : []
|
||||
}
|
||||
|
||||
// 3) 季节性趋势(按月 GMV)
|
||||
const seaRes = await supa.rpc('rpc_analytics_seasonal_trend', {
|
||||
p_start_date: startIso.substring(0, 10),
|
||||
p_end_date: endIso.substring(0, 10)
|
||||
})
|
||||
if (seaRes.status === 404) {
|
||||
console.warn('rpc_analytics_seasonal_trend not found, seasonal trend will be empty')
|
||||
} else if (seaRes.error != null) {
|
||||
console.error('rpc_analytics_seasonal_trend error:', seaRes.error)
|
||||
} else {
|
||||
const sAny = seaRes.data as any
|
||||
seasonalRows = Array.isArray(sAny) ? sAny as Array<UTSJSONObject> : []
|
||||
}
|
||||
|
||||
// 4) 价格趋势(按天平均单价)
|
||||
const priceRes = await supa.rpc('rpc_analytics_price_trend', {
|
||||
p_start: startIso,
|
||||
p_end: endIso
|
||||
})
|
||||
if (priceRes.status === 404) {
|
||||
console.warn('rpc_analytics_price_trend not found, price trend will be empty')
|
||||
} else if (priceRes.error != null) {
|
||||
console.error('rpc_analytics_price_trend error:', priceRes.error)
|
||||
} else {
|
||||
const pAny = priceRes.data as any
|
||||
priceRows = Array.isArray(pAny) ? pAny as Array<UTSJSONObject> : []
|
||||
}
|
||||
|
||||
// 5) 竞争分析(商家 GMV 榜单)
|
||||
const compRes = await supa.rpc('rpc_analytics_competition_share', {
|
||||
p_start_date: startIso.substring(0, 10),
|
||||
p_end_date: endIso.substring(0, 10)
|
||||
})
|
||||
if (compRes.status === 404) {
|
||||
console.warn('rpc_analytics_competition_share not found, competition analysis will be empty')
|
||||
} else if (compRes.error != null) {
|
||||
console.error('rpc_analytics_competition_share error:', compRes.error)
|
||||
} else {
|
||||
const cpAny = compRes.data as any
|
||||
competitionRows = Array.isArray(cpAny) ? cpAny as Array<UTSJSONObject> : []
|
||||
}
|
||||
|
||||
;(this as any)._marketTrendRows = trendRows
|
||||
;(this as any)._industryRows = categoryRows
|
||||
;(this as any)._seasonalRows = seasonalRows
|
||||
;(this as any)._priceRows = priceRows
|
||||
;(this as any)._competitionRows = competitionRows
|
||||
|
||||
this.updateTime()
|
||||
this.buildChartOptions()
|
||||
} catch (e) {
|
||||
console.error('loadMarketData failed:', e)
|
||||
this.updateTime()
|
||||
this.buildChartOptions()
|
||||
uni.showToast({ title: '市场趋势数据加载失败', icon: 'none' })
|
||||
}
|
||||
},
|
||||
|
||||
selectPeriod(p: string) {
|
||||
@@ -178,12 +277,162 @@ export default {
|
||||
},
|
||||
|
||||
buildChartOptions() {
|
||||
// TODO: 构建图表配置
|
||||
this.marketTrendOption = {}
|
||||
this.industryCompareOption = {}
|
||||
this.seasonalTrendOption = {}
|
||||
this.priceTrendOption = {}
|
||||
this.competitionOption = {}
|
||||
const trendAny = (this as any)._marketTrendRows as any
|
||||
const industryAny = (this as any)._industryRows as any
|
||||
const seasonalAny = (this as any)._seasonalRows as any
|
||||
const priceAny = (this as any)._priceRows as any
|
||||
const compAny = (this as any)._competitionRows as any
|
||||
|
||||
const trendRows = Array.isArray(trendAny) ? trendAny as Array<UTSJSONObject> : []
|
||||
const industryRows = Array.isArray(industryAny) ? industryAny as Array<UTSJSONObject> : []
|
||||
const seasonalRows = Array.isArray(seasonalAny) ? seasonalAny as Array<UTSJSONObject> : []
|
||||
const priceRows = Array.isArray(priceAny) ? priceAny as Array<UTSJSONObject> : []
|
||||
const compRows = Array.isArray(compAny) ? compAny as Array<UTSJSONObject> : []
|
||||
|
||||
// 1) 市场整体趋势:GMV / 订单数 / 用户数
|
||||
const mtDays: string[] = []
|
||||
const mtGmv: number[] = []
|
||||
const mtOrders: number[] = []
|
||||
const mtUsers: number[] = []
|
||||
|
||||
for (let i = 0; i < trendRows.length; i++) {
|
||||
const r = trendRows[i]
|
||||
const dayStr = r.getString('day') ?? ''
|
||||
mtDays.push(dayStr.length >= 10 ? dayStr.substring(5, 10) : dayStr)
|
||||
mtGmv.push(r.getNumber('gmv') ?? 0)
|
||||
mtOrders.push(r.getNumber('orders') ?? 0)
|
||||
mtUsers.push(r.getNumber('users') ?? 0)
|
||||
}
|
||||
|
||||
this.marketTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
legend: {
|
||||
data: ['GMV', '订单数', '用户数'],
|
||||
top: 'bottom'
|
||||
},
|
||||
grid: { left: 50, right: 60, top: 40, bottom: 60 },
|
||||
xAxis: { type: 'category', data: mtDays },
|
||||
yAxis: [
|
||||
{ type: 'value', name: 'GMV', splitLine: { lineStyle: { color: '#e5e7eb' } } },
|
||||
{ type: 'value', name: '数量', position: 'right', splitLine: { show: false } }
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: mtGmv,
|
||||
barMaxWidth: 26,
|
||||
itemStyle: { color: '#3b82f6' }
|
||||
},
|
||||
{
|
||||
name: '订单数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtOrders
|
||||
},
|
||||
{
|
||||
name: '用户数',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
smooth: true,
|
||||
data: mtUsers
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 2) 行业对比:分类 GMV
|
||||
const catNames: string[] = []
|
||||
const catSales: number[] = []
|
||||
for (let i = 0; i < industryRows.length; i++) {
|
||||
const r = industryRows[i]
|
||||
catNames.push(r.getString('category_name') ?? '未分类')
|
||||
catSales.push(r.getNumber('total_sales') ?? 0)
|
||||
}
|
||||
this.industryCompareOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 80, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'value' },
|
||||
yAxis: { type: 'category', data: catNames },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'bar',
|
||||
data: catSales
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 3) 季节性趋势:按月 GMV
|
||||
const seaMonths: string[] = []
|
||||
const seaGmv: number[] = []
|
||||
for (let i = 0; i < seasonalRows.length; i++) {
|
||||
const r = seasonalRows[i]
|
||||
seaMonths.push(r.getString('month') ?? '')
|
||||
seaGmv.push(r.getNumber('total_gmv') ?? 0)
|
||||
}
|
||||
this.seasonalTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: seaMonths },
|
||||
yAxis: { type: 'value', name: 'GMV' },
|
||||
series: [
|
||||
{
|
||||
name: 'GMV',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: seaGmv
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 4) 价格趋势:按天平均价格
|
||||
const priceDays: string[] = []
|
||||
const avgPrices: number[] = []
|
||||
for (let i = 0; i < priceRows.length; i++) {
|
||||
const r = priceRows[i]
|
||||
const d = r.getString('day') ?? ''
|
||||
priceDays.push(d.length >= 10 ? d.substring(5, 10) : d)
|
||||
avgPrices.push(r.getNumber('avg_price') ?? 0)
|
||||
}
|
||||
this.priceTrendOption = {
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { left: 50, right: 20, top: 30, bottom: 60 },
|
||||
xAxis: { type: 'category', data: priceDays },
|
||||
yAxis: { type: 'value', name: '平均价格' },
|
||||
series: [
|
||||
{
|
||||
name: '平均价格',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: avgPrices
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// 5) 竞争分析:商家 GMV 对比
|
||||
const merchantNames: string[] = []
|
||||
const merchantGmv: number[] = []
|
||||
for (let i = 0; i < compRows.length; i++) {
|
||||
const r = compRows[i]
|
||||
merchantNames.push(r.getString('merchant_name') ?? '未知商家')
|
||||
merchantGmv.push(r.getNumber('gmv') ?? 0)
|
||||
}
|
||||
this.competitionOption = {
|
||||
tooltip: { trigger: 'item' },
|
||||
legend: { top: 'bottom' },
|
||||
series: [
|
||||
{
|
||||
name: '商家GMV',
|
||||
type: 'pie',
|
||||
radius: ['35%', '65%'],
|
||||
center: ['50%', '50%'],
|
||||
data: merchantNames.map((n, idx) => {
|
||||
return { name: n, value: merchantGmv[idx] }
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
handleMenu() {
|
||||
|
||||
Reference in New Issue
Block a user