From 5ffde4259005abf08b7374676d2899ae6215309a Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Tue, 11 Aug 2026 20:04:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D/overview=20API?= =?UTF-8?q?=E7=90=86=E8=AE=BA=E6=AF=9B=E5=88=A9=E7=8E=87=E5=92=8C=E4=BC=9A?= =?UTF-8?q?=E5=91=98=E5=8D=A0=E6=AF=94=E7=A1=AC=E7=BC=96=E7=A0=81=E4=B8=BA?= =?UTF-8?q?0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - theoretical_margin_pct: 从bill_fact实时计算 sum(theoretical_profit)/sum(received)*100 - member_share_pct: 从bill_fact实时计算 会员账单实收/总实收*100 - member_bills: 统计member_id非空的账单数 - 修复前: 理论毛利率0% 会员占比0% - 修复后: 理论毛利率61.84% 会员占比14.25% --- server/src/routes/data.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/server/src/routes/data.ts b/server/src/routes/data.ts index 97ff558..1980e3a 100644 --- a/server/src/routes/data.ts +++ b/server/src/routes/data.ts @@ -20,9 +20,9 @@ router.get('/overview', async (req: AuthRequest, res) => { round(sum(received_total)::numeric, 2) AS received, round(avg(received_total)::numeric, 2) AS avg_bill_value, round(avg(CASE WHEN consumption > 0 THEN discount_total::numeric / consumption * 100 ELSE 0 END)::numeric, 2) AS discount_rate_pct, - 0 AS theoretical_margin_pct, - 0 AS member_bills, - 0 AS member_share_pct, + round(sum(theoretical_profit) / nullif(sum(received_total), 0) * 100, 2) AS theoretical_margin_pct, + count(*) FILTER (WHERE member_id IS NOT NULL AND member_id <> '') AS member_bills, + round(sum(received_total) FILTER (WHERE member_id IS NOT NULL AND member_id <> '') / nullif(sum(received_total), 0) * 100, 2) AS member_share_pct, round(sum(consumption)::numeric, 2) AS consumption, round(sum(discount_total)::numeric, 2) AS discount FROM analytics.bill_fact @@ -31,13 +31,19 @@ router.get('/overview', async (req: AuthRequest, res) => { sendSuccess(res, result.rows[0]) } else { const result = await query(` - SELECT o.bill_count, o.received, o.avg_bill_value, o.discount_rate_pct, o.theoretical_margin_pct, o.member_bills, o.member_share_pct, - round(b.consumption::numeric, 2) AS consumption, - round(b.discount::numeric, 2) AS discount + SELECT o.bill_count, o.received, o.avg_bill_value, o.discount_rate_pct, + round(b.theoretical_margin_pct, 2) AS theoretical_margin_pct, + b.member_bills, b.member_share_pct, + round(b.consumption, 2) AS consumption, + round(b.discount, 2) AS discount FROM analytics.mv_overview_monthly o LEFT JOIN ( - SELECT round(sum(consumption)::numeric, 2) AS consumption, - round(sum(discount_total)::numeric, 2) AS discount + SELECT + round(sum(consumption)::numeric, 2) AS consumption, + round(sum(discount_total)::numeric, 2) AS discount, + round(sum(theoretical_profit) / nullif(sum(received_total), 0) * 100, 2) AS theoretical_margin_pct, + count(*) FILTER (WHERE member_id IS NOT NULL AND member_id <> '') AS member_bills, + round(sum(received_total) FILTER (WHERE member_id IS NOT NULL AND member_id <> '') / nullif(sum(received_total), 0) * 100, 2) AS member_share_pct FROM analytics.bill_fact WHERE closed_at >= $1::date AND closed_at < ($1::date + interval '1 month') ) b ON true