fix: 老板驾驶舱统一全口径数据源 - 实收/客单价/账单数/风险占比均取自store-expense/overview,与利润瀑布一致

This commit is contained in:
freedakgmail
2026-07-30 14:42:40 +08:00
parent fca917dc13
commit 42e4287473
2 changed files with 7 additions and 4 deletions
+4 -4
View File
@@ -73,7 +73,7 @@ export function BossPage() {
return acc
}, {})
const totalStores = riskRows.length
const totalRev = Number(od?.received || 0)
const totalRev = Number(ex?.total_received || 0)
// P0/P1门店
const p0Stores = priorityRows.filter((s: any) => s.action_priority?.startsWith('P0'))
@@ -155,10 +155,10 @@ export function BossPage() {
{/* ① 核心经营指标 */}
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
<MetricCard title="实收总额" value={od?.received} format="currency" trend={trendReceived} description={`公式:全部门店实收合计。环比上周 ${trendReceived > 0 ? '↑' : '↓'} ${Math.abs(trendReceived)}%`} />
<MetricCard title="实收总额" value={ex?.total_received} format="currency" trend={trendReceived} description={`全口径${ex?.total_stores}家门店。公式:全部门店实收合计。环比上周 ${trendReceived > 0 ? '↑' : '↓'} ${Math.abs(trendReceived)}%`} />
<MetricCard title="实际净利润" value={ex?.actual_net_profit} format="currency" status={Number(ex?.actual_net_margin_pct) < 5 ? 'bad' : Number(ex?.actual_net_margin_pct) < 10 ? 'warn' : 'good'} description={`净利率 ${formatPercent(ex?.actual_net_margin_pct)} · 公式:实收 - 食材成本 - 经营费用。建议值:≥ 10% 优秀,5-10% 合格,< 5% 需整改`} />
<MetricCard title="门店数" value={totalStores} unit="家" description={`盈利 ${ex?.profitable_stores}家 / 亏损 ${ex?.loss_stores}家。无费用数据 ${ex?.no_expense_stores}`} />
<MetricCard title="客单价" value={od?.avg_bill_value} format="currency" trend={trend((last7.length > 0 ? sumKey(last7, 'received') / sumKey(last7, 'bill_count') : 0), (prev7.length > 0 ? sumKey(prev7, 'received') / sumKey(prev7, 'bill_count') : 0))} description={`账单 ${formatNumber(od?.bill_count)} 笔 · 公式:实收 ÷ 账单数`} />
<MetricCard title="门店数" value={ex?.total_stores} unit="家" description={`盈利 ${ex?.profitable_stores}家 / 亏损 ${ex?.loss_stores}家。无费用数据 ${ex?.no_expense_stores}`} />
<MetricCard title="客单价" value={ex?.avg_bill_value} format="currency" trend={trend((last7.length > 0 ? sumKey(last7, 'received') / sumKey(last7, 'bill_count') : 0), (prev7.length > 0 ? sumKey(prev7, 'received') / sumKey(prev7, 'bill_count') : 0))} description={`账单 ${formatNumber(ex?.total_bills)} 笔 · 公式:实收 ÷ 账单数`} />
</div>
{/* ② 利润瀑布 */}
+3
View File
@@ -16,6 +16,7 @@ router.get('/overview', async (req: AuthRequest, res) => {
r.store_code,
r.store_name,
r.received,
r.bill_count,
r.theoretical_margin_pct,
COALESCE(e.operating_expense, 0) AS operating_expense,
COALESCE(e.wage_expense, 0) AS wage_expense,
@@ -40,7 +41,9 @@ router.get('/overview', async (req: AuthRequest, res) => {
count(*) FILTER (WHERE actual_store_contribution > 0) AS profitable_stores,
count(*) FILTER (WHERE actual_store_contribution <= 0 AND received > 0) AS loss_stores,
count(*) FILTER (WHERE operating_expense = 0) AS no_expense_stores,
sum(bill_count)::bigint AS total_bills,
round(sum(received)::numeric, 2) AS total_received,
round(sum(received) / nullif(sum(bill_count), 0), 2) AS avg_bill_value,
round(sum(operating_expense)::numeric, 2) AS total_expense,
round(sum(wage_expense)::numeric, 2) AS total_wage,
round(sum(rent_expense)::numeric, 2) AS total_rent,