14 · 技术参考:全页面数据溯源审计报告
目标:逐页面、逐指标追溯显示名称 → API → SQL → 数据源表字段,标出跨页面重复指标口径是否一致。
一、页面与 API 总览
| 页面 |
文件 |
调用的 API |
| 总部驾驶舱 |
DashboardPage.tsx |
/overview, /overview/daily, /stores/risk, /stores/priority, /tasks/loop-health, /stores/quadrant, /platform/economics, /situational-awareness/alerts, /store-expense/overview, /overview/yoy, /overview/mom, /overview/trend, /overview/profit-trend |
| 老板驾驶舱 |
BossPage.tsx |
/overview, /overview/daily, /store-expense/overview, /overview/profit-waterfall, /stores/risk, /stores/priority, /cost-analysis/store-overview, /store-expense/expense-structure, /overview/store-profit-ranking, /overview/profit-opportunity |
| 门店工作台 |
StorePage.tsx |
/stores/risk, /stores/priority, /tasks/stores/:code/daily-card, /tasks, /stores/:code/daily, /tasks/followup, /sku/attach, /sku/abc, /stores/:code, /situational-awareness/health-score, /stores/:code/meal-period, /stores/:code/category-mix, /stores/:code/cost, /stores/:code/member, /stores/:code/anomalies, /stores/:code/staffing |
| 成本分析 |
CostPage.tsx |
/cost/comparison, /cost/inventory, /cost/category-benchmark |
| 成本分析(Tab) |
cost-analysis/*.tsx |
/cost-analysis/overview, /category-comparison, /margin-deviation, /variance-top, /menu-engineering, /profitability, /pricing, /store-overview, /store-ranking, /bom-, /packaging-, /material-, /data-quality, /unmatched- |
| 费用分析(Tab) |
store-expense/*.tsx |
/store-expense/overview, /expense-structure, /store-ranking, /store-contribution, /break-even, /loss-diagnosis, /delivery-commission, /rent-risk, /fixed-variable, /efficiency, /store-evaluation |
| 风险监控 |
RiskPage.tsx |
/risk/anomaly, /risk/zero-received, /risk/cashier |
| 会员复购 |
MemberPage.tsx |
/member/comparison, /member/repeat |
| SKU分析 |
SKUPage.tsx |
/sku/abc, /sku/category |
| 菜单工程 |
MenuEngineeringPage.tsx |
/analytics-enhanced/menu-engineering/actions |
| 产品生命周期 |
ProductLifecyclePage.tsx |
/product/products, /product/reviews/overview, /product/reviews |
| BOM穿透 |
BomPenetrationPage.tsx |
/central-kitchen/bom-penetration |
| 分销对账 |
DistributionReconciliationPage.tsx |
/distribution/reconciliation |
| 生产计划 |
ProductionPlanPage.tsx |
/sales-driven/production-plan |
| 任务闭环 |
TasksPage.tsx |
/tasks |
| 数据导入 |
DataImportPage.tsx |
/product/import-logs, /product/quality-rules |
| 本体浏览 |
OntologyPage.tsx |
/tasks/ontology/* |
二、页面1:总部驾驶舱 DashboardPage
无Tab,用 CollapsibleSection 分区。共调用13个API。
区块①:门店风险分布条
| 显示指标 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表.字段 |
| 红色门店数 |
riskSummary['红色'] |
/stores/risk |
risk_level |
SELECT * FROM mv_store_risk_rating_monthly |
analytics.mv_store_risk_rating_monthly.risk_level |
| 黄色门店数 |
riskSummary['黄色'] |
同上 |
同上 |
同上 |
同上 |
| 绿色门店数 |
riskSummary['绿色'] |
同上 |
同上 |
同上 |
同上 |
| 总门店数 |
totalStores = riskRows.length |
同上 |
行数 |
同上 |
同上 |
区块②:态势感知预警
| 显示指标 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表 |
| 红色预警数 |
alertSummary.red |
/situational-awareness/alerts |
red |
5类预警合并: 营收异动/成本异动/人力异动/平台依赖/任务逾期 |
mv_daily_revenue, dish_cost_analysis_summary, salary_detail_records, mv_store_platform_economics_monthly, store_task |
| 橙色预警数 |
alertSummary.orange |
同上 |
orange |
同上 |
同上 |
| 预警总数 |
alertSummary.total |
同上 |
total |
同上 |
同上 |
| 预警列表(前6条) |
alerts.slice(0,6) |
同上 |
alerts[] |
同上,每条含 title/detail/level |
同上 |
区块③:经营指标
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表.字段 |
| 营业收入 |
od?.consumption |
/overview |
consumption |
sum(consumption) |
analytics.bill_fact.consumption |
| 优惠 |
od?.discount |
/overview |
discount |
sum(discount_total) |
analytics.bill_fact.discount_total |
| 实收 |
od?.received |
/overview |
received |
sum(received_total) |
analytics.bill_fact.received_total |
| 账单数 |
od?.bill_count |
/overview |
bill_count |
count(*) |
analytics.bill_fact |
| 客单价 |
od?.avg_bill_value |
/overview |
avg_bill_value |
avg(received_total) |
analytics.bill_fact.received_total |
| P0+P1门店数 |
p0p1Stores.length |
/stores/priority |
行数过滤 |
action_priority LIKE 'P0%' OR 'P1%' |
analytics.mv_store_action_priority_deep_monthly.action_priority |
| 实收环比趋势 |
trendReceived |
/overview/daily |
前端计算 |
(last7days.received - prev7days.received) / prev7days.received * 100 |
analytics.mv_overview_daily.received |
| 账单数环比趋势 |
trendBills |
/overview/daily |
前端计算 |
同上,用 bill_count |
analytics.mv_overview_daily.bill_count |
| 客单价环比趋势 |
trendAvgBill |
/overview/daily |
前端计算 |
last7.avg - prev7.avg |
analytics.mv_overview_daily |
区块④:运营指标
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表.字段 |
| 优惠率 |
od?.discount_rate_pct |
/overview |
discount_rate_pct |
avg(discount_total / consumption * 100) per bill |
analytics.bill_fact.discount_total, consumption |
| 理论毛利率 |
od?.theoretical_margin_pct |
/overview |
theoretical_margin_pct |
sum(theoretical_profit) / sum(received_total) * 100 |
analytics.bill_fact.theoretical_profit, received_total |
| 会员占比 |
od?.member_share_pct |
/overview |
member_share_pct |
sum(received_total) FILTER(member_id非空) / sum(received_total) * 100 |
analytics.bill_fact.received_total, member_id |
区块⑤:同比/环比对比
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 实收同比% |
yoyData_.received_change_pct |
/overview/yoy |
yoy.received_change_pct |
`(当月received - 去年同月received) / |
去年同月received |
| 实收环比% |
momData_.received_change_pct |
/overview/mom |
mom.received_change_pct |
`(当月received - 上月received) / |
上月received |
| 账单数同比% |
yoyData_.bill_count_change_pct |
/overview/yoy |
yoy.bill_count_change_pct |
同上,用 bill_count |
analytics.mv_overview_monthly.bill_count |
| 账单数环比% |
momData_.bill_count_change_pct |
/overview/mom |
mom.bill_count_change_pct |
同上 |
analytics.mv_overview_monthly.bill_count |
| 客单价同比% |
yoyData_.avg_bill_value_change_pct |
/overview/yoy |
yoy.avg_bill_value_change_pct |
同上,用 avg_bill_value |
analytics.mv_overview_monthly.avg_bill_value |
| 客单价环比% |
momData_.avg_bill_value_change_pct |
/overview/mom |
mom.avg_bill_value_change_pct |
同上 |
analytics.mv_overview_monthly.avg_bill_value |
| 优惠率同比变化 |
yoyData_.discount_rate_change |
/overview/yoy |
yoy.discount_rate_change |
当月discount_rate_pct - 去年同月discount_rate_pct |
analytics.mv_overview_monthly.discount_rate_pct |
| 优惠率环比变化 |
momData_.discount_rate_change |
/overview/mom |
mom.discount_rate_change |
当月 - 上月 |
analytics.mv_overview_monthly.discount_rate_pct |
区块⑥:利润与成本
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 理论贡献利润 |
ex.theoretical_net_profit |
/store-expense/overview |
theoretical_net_profit |
sum(received) FILTER(费用匹配) - sum(theoretical_cost) - sum(operating_expense) |
mv_store_risk_rating_monthly.received + mv_store_operating_expense_monthly |
| 理论贡献率 |
ex.theoretical_net_margin_pct |
同上 |
theoretical_net_margin_pct |
theoretical_net_profit / matched_received * 100 |
同上 |
| 实际贡献利润 |
ex.actual_net_profit |
同上 |
actual_net_profit |
sum(received) FILTER(费用匹配) - sum(actual_food_cost) - sum(operating_expense) |
同上 |
| 实际贡献率 |
ex.actual_net_margin_pct |
同上 |
actual_net_margin_pct |
actual_net_profit / matched_received * 100 |
同上 |
| 盈利门店数 |
ex.profitable_stores |
同上 |
profitable_stores |
count(*) FILTER(actual_store_contribution > 0) |
同上 |
| 亏损门店数 |
ex.loss_stores |
同上 |
loss_stores |
count(*) FILTER(actual_store_contribution <= 0 AND received > 0) |
同上 |
| 食材成本 |
ex.total_food_cost |
同上 |
total_food_cost |
sum(actual_food_cost) |
mv_store_operating_expense_monthly.actual_food_cost |
| 实际食材成本率 |
ex.actual_food_cost_rate_pct |
同上 |
actual_food_cost_rate_pct |
sum(actual_food_cost) / matched_received * 100 |
同上 |
| 理论食材成本率 |
ex.theoretical_food_cost_rate_pct |
同上 |
theoretical_food_cost_rate_pct |
sum(theoretical_cost) / matched_received * 100 |
同上 |
| 经营费用 |
ex.total_expense |
同上 |
total_expense |
sum(operating_expense) |
mv_store_operating_expense_monthly.operating_expense |
| 费用率 |
ex.overall_expense_rate_pct |
同上 |
overall_expense_rate_pct |
sum(operating_expense) / matched_received * 100 |
同上 |
| 人工费用 |
ex.total_wage |
同上 |
total_wage |
sum(wage_expense) |
mv_store_operating_expense_monthly.wage_expense |
| 人工费率 |
ex.overall_wage_rate_pct |
同上 |
overall_wage_rate_pct |
sum(wage_expense) / matched_received * 100 |
同上 |
| 房租费用 |
ex.total_rent |
同上 |
total_rent |
sum(rent_expense) |
mv_store_operating_expense_monthly.rent_expense |
| 房租费率 |
ex.overall_rent_rate_pct |
同上 |
overall_rent_rate_pct |
sum(rent_expense) / matched_received * 100 |
同上 |
| 水电费用 |
ex.total_utility |
同上 |
total_utility |
sum(utility_expense) |
mv_store_operating_expense_monthly.utility_expense |
| 水电费率 |
ex.overall_utility_rate_pct |
同上 |
overall_utility_rate_pct |
sum(utility_expense) / matched_received * 100 |
同上 |
| 外卖佣金 |
ex.total_commission |
同上 |
total_commission |
sum(delivery_commission_expense) |
mv_store_operating_expense_monthly.delivery_commission_expense |
| 外卖佣金占实收 |
前端计算 |
同上 |
前端除法 |
total_commission / total_received * 100 |
同上 |
区块⑦:闭环健康度
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 综合得分 |
loopScore (前端5项平均) |
/tasks/loop-health |
5个rate字段 |
analytics.mv_loop_health |
| 任务生成率 |
lh.task_generation_rate |
同上 |
task_generation_rate |
analytics.mv_loop_health.task_generation_rate |
| 店长执行率 |
lh.store_execution_rate |
同上 |
store_execution_rate |
analytics.mv_loop_health.store_execution_rate |
| 区域周检率 |
lh.weekly_check_rate |
同上 |
weekly_check_rate |
analytics.mv_loop_health.weekly_check_rate |
| 月度验收率 |
lh.monthly_review_rate |
同上 |
monthly_review_rate |
analytics.mv_loop_health.monthly_review_rate |
| 经验推广率 |
lh.practice_promotion_rate |
同上 |
practice_promotion_rate |
analytics.mv_loop_health.practice_promotion_rate |
区块⑧:图表区 - 日度实收趋势
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 日度实收折线 |
dailyRows[].received |
/overview/daily |
received |
analytics.mv_overview_daily.received (无scope) 或 bill_fact (有scope) |
| 日期 |
dailyRows[].business_date |
同上 |
business_date |
analytics.mv_overview_daily.business_date |
区块⑨:图表区 - 门店风险分级分布
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 风险分布饼图 |
riskPieData |
/stores/risk |
risk_level |
analytics.mv_store_risk_rating_monthly.risk_level |
区块⑩:图表区 - 门店经营象限
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| X轴: 日均实收 |
quadrantScatterData.x = r.avg_daily_received |
/stores/quadrant |
avg_daily_received |
analytics.mv_store_benchmark_composite_monthly.avg_daily_received |
| Y轴: 毛利率 |
quadrantScatterData.y = r.theoretical_margin_pct |
同上 |
theoretical_margin_pct |
analytics.mv_store_benchmark_composite_monthly.theoretical_margin_pct |
| 象限分类 |
r.management_quadrant |
同上 |
management_quadrant |
analytics.mv_store_benchmark_composite_monthly.management_quadrant |
区块⑪:图表区 - P0/P1实收覆盖瀑布图
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| P0门店实收 |
p0Received |
/stores/priority |
received |
sum(received) FILTER(action_priority LIKE 'P0%') |
analytics.mv_store_action_priority_deep_monthly.received |
| P1门店实收 |
p1Received |
/stores/priority |
received |
sum(received) FILTER(action_priority LIKE 'P1%') |
同上 |
| 其他门店实收 |
otherReceived = od.received - p0Received - p1Received |
/overview + /stores/priority |
前端计算 |
总实收 - P0 - P1 |
bill_fact + mv_store_action_priority_deep_monthly |
| 合计实收 |
od?.received |
/overview |
received |
sum(received_total) |
analytics.bill_fact.received_total |
区块⑫:图表区 - 平台成本率TOP15
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 美团成本率 |
r.meituan_cost_rate_pct |
/platform/economics |
meituan_cost_rate_pct |
analytics.mv_store_platform_economics_monthly.meituan_cost_rate_pct |
| 饿了么成本率 |
r.eleme_cost_rate_pct |
同上 |
eleme_cost_rate_pct |
analytics.mv_store_platform_economics_monthly.eleme_cost_rate_pct |
| 抖音成本率 |
r.douyin_cost_rate_pct |
同上 |
douyin_cost_rate_pct |
analytics.mv_store_platform_economics_monthly.douyin_cost_rate_pct |
区块⑬:月度经营趋势
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 月度实收折线 |
trendRows[].received |
/overview/trend |
received |
analytics.mv_overview_monthly.received |
| 月度账单数柱状 |
trendRows[].bill_count |
同上 |
bill_count |
analytics.mv_overview_monthly.bill_count |
区块⑭:利润趋势
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 月度实收 |
profitTrendRows[].received |
/overview/profit-trend |
received |
sum(r.received) |
v_store_scorecard.received |
| 食材成本 |
profitTrendRows[].food_cost |
同上 |
food_cost |
sum(COALESCE(e.actual_food_cost, 0)) |
mv_store_operating_expense_monthly.actual_food_cost |
| 人工 |
profitTrendRows[].wage |
同上 |
wage |
sum(COALESCE(e.wage_expense, 0)) |
mv_store_operating_expense_monthly.wage_expense |
| 房租 |
profitTrendRows[].rent |
同上 |
rent |
sum(COALESCE(e.rent_expense, 0)) |
mv_store_operating_expense_monthly.rent_expense |
| 水电 |
profitTrendRows[].utility |
同上 |
utility |
sum(COALESCE(e.utility_expense, 0)) |
mv_store_operating_expense_monthly.utility_expense |
| 贡献利润 |
profitTrendRows[].store_contribution |
同上 |
store_contribution |
sum(r.received) - sum(food_cost) - sum(operating_expense) |
同上 |
⚠️ profit-trend 口径注意:该API用 v_store_scorecard JOIN mv_store_operating_expense_monthly,WHERE e.report_month >= $1 AND <= $2。LEFT JOIN后WHERE过滤掉无费用门店(e.report_month IS NULL),所以实际只含费用匹配门店,口径与 store-expense/overview 一致。但COALESCE(...,0)是多余的(不会出现NULL行)。
区块⑮:P0/P1重点整改门店列表
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 门店名 |
r.store_name |
/stores/priority |
store_name |
analytics.mv_store_action_priority_deep_monthly.store_name |
| 优先级 |
r.action_priority |
同上 |
action_priority |
同上 |
| 问题数 |
r.problem_count |
同上 |
problem_count |
同上 |
| 问题组合 |
r.problem_combination |
同上 |
problem_combination |
同上 |
| 实收 |
r.received |
同上 |
received |
同上 |
三、跨页面核心指标溯源与口径对比
3.1 营业收入(消费金额)
| 页面 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表.字段 |
| 总部驾驶舱 |
od?.consumption |
/overview |
consumption |
sum(consumption) from bill_fact |
analytics.bill_fact.consumption |
| 老板驾驶舱 |
od?.consumption |
/overview |
consumption |
同上 |
同上 |
| 费用总览Tab |
ov.total_consumption |
/store-expense/overview |
total_consumption |
sum(consumption) from bill_fact CTE |
analytics.bill_fact.consumption |
口径:一致 ✅ — 三个页面均来自 analytics.bill_fact.consumption 的月度汇总。
3.2 优惠
| 页面 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表.字段 |
| 总部驾驶舱 |
od?.discount |
/overview |
discount |
sum(discount_total) from bill_fact |
analytics.bill_fact.discount_total |
| 老板驾驶舱 |
od?.discount |
/overview |
discount |
同上 |
同上 |
| 费用总览Tab |
ov.total_discount |
/store-expense/overview |
total_discount |
sum(discount_total) from bill_fact CTE |
analytics.bill_fact.discount_total |
口径:一致 ✅(已修复,BossPage 之前用 ex?.total_discount 也一致)
3.3 实收
| 页面 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表.字段 |
| 总部驾驶舱 |
od?.received |
/overview |
received |
sum(received_total) from bill_fact |
analytics.bill_fact.received_total |
| 老板驾驶舱 |
od?.received |
/overview |
received |
同上 |
同上 |
| 费用总览Tab |
ov.total_received |
/store-expense/overview |
total_received |
sum(r.received) from mv_store_risk_rating_monthly |
analytics.mv_store_risk_rating_monthly.received |
| 利润瀑布 |
wf.received |
/overview/profit-waterfall |
received |
sum(r.received) from mv_store_risk_rating_monthly |
analytics.mv_store_risk_rating_monthly.received |
口径:一致 ✅(已修复)— bill_fact.received_total 汇总和 mv_store_risk_rating_monthly.received 汇总结果相同(均为 64,409,339.09),因为后者物化视图就来自前者。
3.4 账单数
| 页面 |
前端变量 |
API |
API字段 |
SQL来源 |
数据源表.字段 |
| 总部驾驶舱 |
od?.bill_count |
/overview |
bill_count |
count(*) from bill_fact |
analytics.bill_fact |
| 老板驾驶舱 |
ex?.total_bills |
/store-expense/overview |
total_bills |
sum(bill_count) from mv_store_risk_rating_monthly |
analytics.mv_store_risk_rating_monthly.bill_count |
口径:一致 ✅ — 值均为 1,682,360。
3.5 客单价
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
od?.avg_bill_value |
/overview |
avg_bill_value |
avg(received_total) from bill_fact = 38.29 |
| 老板驾驶舱 |
ex?.avg_bill_value |
/store-expense/overview |
avg_bill_value |
sum(received)/sum(bill_count) = 38.29 |
口径:一致 ✅ — 数学结果相同。
3.6 优惠率
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
od?.discount_rate_pct |
/overview |
discount_rate_pct |
avg(discount_total/consumption*100) from bill_fact = 19.52% |
| 老板驾驶舱 |
无(不显示此指标) |
- |
- |
- |
口径:N/A — 仅总部驾驶舱显示。
3.7 理论毛利率
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
od?.theoretical_margin_pct |
/overview |
theoretical_margin_pct |
sum(theoretical_profit)/sum(received)*100 from bill_fact = 61.84% |
口径:N/A — 仅总部驾驶舱显示。(已修复,之前硬编码为0)
3.8 会员占比
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
od?.member_share_pct |
/overview |
member_share_pct |
sum(received_total) FILTER(member_id非空)/sum(received_total)*100 = 14.25% |
口径:N/A — 仅总部驾驶舱显示。(已修复,之前硬编码为0)
3.9 门店贡献利润(实际)
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
值 |
| 总部驾驶舱 |
ex?.actual_net_profit |
/store-expense/overview |
actual_net_profit |
sum(received) FILTER(费用匹配) - sum(food_cost) - sum(operating_expense) |
6,982,110.42 |
| 老板驾驶舱(指标卡) |
ex?.actual_net_profit |
/store-expense/overview |
actual_net_profit |
同上 |
6,982,110.42 |
| 老板驾驶舱(瀑布图) |
wf.store_contribution |
/overview/profit-waterfall |
store_contribution |
sum(received) FILTER(has_expense) - sum(food_cost) - sum(operating_expense) |
6,982,110.42 |
口径:一致 ✅(已修复)— 瀑布图已改为仅含 has_expense 门店。
3.10 贡献率(实际)
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
值 |
| 总部驾驶舱 |
ex?.actual_net_margin_pct |
/store-expense/overview |
actual_net_margin_pct |
(matched_received - food_cost - operating_expense)/matched_received*100 |
10.96% |
| 老板驾驶舱(指标卡) |
ex?.actual_net_margin_pct |
/store-expense/overview |
actual_net_margin_pct |
同上 |
10.96% |
| 老板驾驶舱(瀑布图) |
前端计算 wf.store_contribution/wf.received*100 |
/overview/profit-waterfall |
前端除法 |
6982110/63687977*100 |
10.96% |
口径:一致 ✅(已修复)— 瀑布图 received 和 contribution 均改为仅含 has_expense 门店。
3.11 食材成本
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
ex?.total_food_cost |
/store-expense/overview |
total_food_cost |
sum(actual_food_cost) from mv_store_operating_expense_monthly |
| 老板驾驶舱(瀑布图) |
wf.food_cost |
/overview/profit-waterfall |
food_cost |
sum(COALESCE(actual_food_cost,0)) — 含2家0值门店 |
| 费用总览Tab |
ov.total_food_cost |
/store-expense/overview |
total_food_cost |
同总部 |
口径:一致 ✅ — 2家无费用门店的 food_cost 为 NULL,sum(NULL) 忽略,sum(COALESCE(NULL,0)) 加0,结果相同。
3.12 食材成本率
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
值 |
| 总部驾驶舱 |
ex?.actual_food_cost_rate_pct |
/store-expense/overview |
actual_food_cost_rate_pct |
sum(food_cost)/matched_received*100 |
35.26% |
| 老板驾驶舱(瀑布图) |
前端计算 wf.food_cost/wf.received*100 |
/overview/profit-waterfall |
前端除法 |
22459074/63687977*100 |
35.26% |
口径:一致 ✅(已修复)— 瀑布图 received 改为 matched 口径。
3.13 经营费用
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
ex?.total_expense |
/store-expense/overview |
total_expense |
sum(operating_expense) — NULL被sum忽略 |
| 老板驾驶舱(瀑布图) |
wf.total_expense |
/overview/profit-waterfall |
total_expense |
sum(COALESCE(operating_expense,0)) — 2家为0 |
| 费用总览Tab |
ov.total_expense |
/store-expense/overview |
total_expense |
同总部 |
口径:一致 ✅ — sum忽略NULL vs COALESCE加0,结果相同。
3.14 费用率
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
值 |
| 总部驾驶舱 |
ex?.overall_expense_rate_pct |
/store-expense/overview |
overall_expense_rate_pct |
sum(operating_expense)/matched_received*100 |
53.77% |
| 老板驾驶舱(瀑布图) |
前端计算 wf.total_expense/wf.received*100 |
/overview/profit-waterfall |
前端除法 |
34246793/63687977*100 |
53.77% |
| 费用总览Tab |
ov.overall_expense_rate_pct |
/store-expense/overview |
overall_expense_rate_pct |
同总部 |
53.77% |
口径:一致 ✅(已修复)— 瀑布图分母改为 matched 口径。
3.15 人工费用 / 人工费率
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
ex?.total_wage / ex?.overall_wage_rate_pct |
/store-expense/overview |
total_wage / overall_wage_rate_pct |
sum(wage_expense) / sum(wage)/matched_received*100 |
| 老板驾驶舱(瀑布图) |
wf.wage |
/overview/profit-waterfall |
wage |
sum(COALESCE(wage_expense,0)) |
| 费用总览Tab |
ov.total_wage / ov.overall_wage_rate_pct |
/store-expense/overview |
同总部 |
同总部 |
金额口径:一致 ✅ — sum忽略NULL vs COALESCE加0结果相同。
费率口径:一致 ✅(已修复)— 瀑布图 received 改为 matched 口径后,前端除法分母一致。
3.16 房租费用 / 房租费率
同 3.15,金额一致,费率已修复一致。
3.17 水电费用 / 水电费率
同 3.15,金额一致,费率已修复一致。
3.18 外卖佣金
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
ex?.total_commission |
/store-expense/overview |
total_commission |
sum(delivery_commission_expense) |
| 老板驾驶舱(瀑布图) |
wf.commission |
/overview/profit-waterfall |
commission |
sum(COALESCE(delivery_commission_expense,0)) |
口径:一致 ✅ — 金额相同。
3.19 门店数
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
riskRows.length |
/stores/risk |
count of rows |
count(*) from mv_store_risk_rating_monthly |
| 老板驾驶舱 |
ex?.total_stores |
/store-expense/overview |
total_stores |
count(*) from full_scope (mv_store_risk_rating_monthly) |
口径:一致 ✅ — 均为94家。
3.20 盈利/亏损门店数
| 页面 |
前端变量 |
API |
API字段 |
计算方式 |
| 总部驾驶舱 |
ex?.profitable_stores / ex?.loss_stores |
/store-expense/overview |
profitable_stores / loss_stores |
count(*) FILTER(actual_store_contribution>0) / count(*) FILTER(<=0 AND received>0) |
| 老板驾驶舱 |
同上 |
同上 |
同上 |
同上 |
口径:一致 ✅ — 盈利78家/亏损13家。
3.21 门店风险分布
| 页面 |
前端变量 |
API |
数据源 |
| 总部驾驶舱 |
riskSummary |
/stores/risk |
analytics.mv_store_risk_rating_monthly.risk_level |
| 老板驾驶舱 |
riskSummary |
/stores/risk |
同上 |
口径:一致 ✅
3.22 P0/P1 门店
| 页面 |
前端变量 |
API |
数据源 |
| 总部驾驶舱 |
priorityRows |
/stores/priority |
analytics.mv_store_action_priority_deep_monthly |
| 老板驾驶舱 |
priorityRows |
/stores/priority |
同上 |
口径:一致 ✅
3.23 成本异常分布
| 页面 |
前端变量 |
API |
数据源 |
| 老板驾驶舱 |
costOv.red_count 等 |
/cost-analysis/store-overview |
analytics.mv_store_theoretical_actual_cost_monthly |
| 成本分析Tab |
同上 |
同上 |
同上 |
口径:一致 ✅
3.24 利润机会池
| 页面 |
前端变量 |
API |
数据源 |
| 老板驾驶舱 |
profitOpp |
/overview/profit-opportunity |
analytics.mv_store_risk_rating_monthly + mv_store_operating_expense_monthly |
口径:N/A — 仅老板驾驶舱显示。
3.25 日度趋势
| 页面 |
前端变量 |
API |
数据源 |
| 总部驾驶舱 |
dailyRows |
/overview/daily |
analytics.mv_overview_daily 或 bill_fact |
| 老板驾驶舱 |
dailyRows |
/overview/daily |
同上 |
口径:一致 ✅
三、发现的问题汇总
问题1:利润瀑布 store_contribution 口径不一致 ✅ 已修复
位置:/overview/profit-waterfall API (data.ts:1082)
已修复:received/consumption/discount/store_contribution 均改为 FILTER (WHERE has_expense),仅含92家匹配门店,与 store-expense/overview 一致。
问题2:利润瀑布各项费率分母不一致 ✅ 已修复
已修复:瀑布图 received 改为 matched 口径后,前端除法分母与 store-expense/overview 一致。
问题3:mv_overview_monthly 刷新机制不完整 ✅ 已修复
现状:mv_overview_monthly 是普通表(非物化视图),之前刷新脚本未包含它的更新步骤,导致数据导入后该表不更新。
已修复:刷新脚本已加入 DELETE+INSERT 步骤。
问题4:KPI达成率利润口径不一致 ⚠️ 待确认
位置:/analytics-enhanced/kpi API (analytics-enhanced.ts:944-953)
现状:
actual_revenue = sum(r.received) — 包含全部94家门店
actual_profit = sum(e.actual_store_contribution) — LEFT JOIN后NULL被sum忽略,实际只含92家有费用门店
profit_margin_pct = actual_profit / actual_revenue * 100 — 分子92家/分母94家,偏低
影响:利润率指标偏低(分母多含2家无费用门店的实收429万),但影响较小(~0.7pp)。
问题5:store-profit-ranking 用COALESCE导致无费用门店排名异常 ⚠️ 待确认
位置:/overview/store-profit-ranking API (data.ts:1094-1112)
现状:store_contribution = r.received - COALESCE(e.actual_food_cost,0) - COALESCE(e.operating_expense,0),2家无费用门店的贡献利润 = received - 0 - 0 = received(全部实收算作利润),会排在利润TOP5最前面。
影响:BossPage利润排名TOP5可能包含无费用门店,显示"贡献利润=实收"的异常数据。
问题6:StorePage公司均值硬编码 ⚠️ 待确认
位置:StorePage.tsx:188 — companyAvg 对象
现状:8个指标的公司均值全部硬编码(日均营收20144、客单价36.8、优惠率20.5%等),不随数据更新而变化。
影响:如果实际公司均值发生变化,偏差对比将不准确。建议改为API动态获取。
问题7:StorePage scorecard 直接查bill_records而非物化视图 ⚠️ 待确认
位置:/stores/:code API (data.ts:177-196)
现状:scorecard 直接从 bill_records 原始表聚合查询,而其他页面用 mv_store_risk_rating_monthly 物化视图。
影响:两表同月数据应一致,但若物化视图刷新不及时可能存在差异。且直接查原始表性能较差。
四、页面2:老板驾驶舱 BossPage
无Tab,用区块布局。共调用10个API + KPISection组件1个API。
区块①:核心经营指标(6个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
od?.consumption |
/overview |
consumption |
sum(consumption) |
analytics.bill_fact.consumption |
| 优惠 |
od?.discount |
/overview |
discount |
sum(discount_total) |
analytics.bill_fact.discount_total |
| 实收总额 |
od?.received |
/overview |
received |
sum(received_total) |
analytics.bill_fact.received_total |
| 实收环比趋势 |
trendReceived |
/overview/daily |
前端计算 |
(last7.received - prev7.received) / prev7.received * 100 |
analytics.mv_overview_daily.received |
| 门店贡献利润估算 |
ex?.actual_net_profit |
/store-expense/overview |
actual_net_profit |
sum(received) FILTER(费用匹配) - sum(food_cost) - sum(operating_expense) |
mv_store_risk_rating_monthly + mv_store_operating_expense_monthly |
| 贡献率(描述) |
ex?.actual_net_margin_pct |
/store-expense/overview |
actual_net_margin_pct |
actual_net_profit / matched_received * 100 |
同上 |
| 门店数 |
ex?.total_stores |
/store-expense/overview |
total_stores |
count(*) |
mv_store_risk_rating_monthly |
| 盈利门店数(描述) |
ex?.profitable_stores |
/store-expense/overview |
profitable_stores |
count(*) FILTER(actual_store_contribution > 0) |
同上 |
| 亏损门店数(描述) |
ex?.loss_stores |
/store-expense/overview |
loss_stores |
count(*) FILTER(<=0 AND received>0) |
同上 |
| 客单价 |
ex?.avg_bill_value |
/store-expense/overview |
avg_bill_value |
sum(received) / sum(bill_count) |
同上 |
| 客单价环比趋势 |
前端计算 |
/overview/daily |
前端计算 |
last7.avg - prev7.avg |
analytics.mv_overview_daily |
| 账单数(描述) |
ex?.total_bills |
/store-expense/overview |
total_bills |
sum(bill_count) |
mv_store_risk_rating_monthly.bill_count |
区块①b:KPI达成率(KPISection组件)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 收入达成率 |
kpi.revenue_achievement_pct |
/analytics-enhanced/kpi |
revenue_achievement_pct |
sum(r.received) / sum(t.revenue_target) * 100 |
mv_store_risk_rating_monthly.received + dim_store_target.revenue_target |
| 利润达成率 |
kpi.profit_achievement_pct |
同上 |
profit_achievement_pct |
sum(e.actual_store_contribution) / sum(t.profit_target) * 100 |
mv_store_operating_expense_monthly.actual_store_contribution + dim_store_target.profit_target |
| 目标收入 |
kpi.revenue_target |
同上 |
revenue_target |
sum(t.revenue_target) |
dim_store_target.revenue_target |
| 利润率 |
kpi.profit_margin_pct |
同上 |
profit_margin_pct |
sum(actual_store_contribution) / sum(received) * 100 |
同上 |
| 目标利润(图表) |
kpi.profit_target |
同上 |
profit_target |
sum(t.profit_target) |
dim_store_target.profit_target |
| 实际收入(图表) |
kpi.actual_revenue |
同上 |
actual_revenue |
sum(r.received) |
mv_store_risk_rating_monthly.received |
| 实际利润(图表) |
kpi.actual_profit |
同上 |
actual_profit |
sum(e.actual_store_contribution) |
mv_store_operating_expense_monthly.actual_store_contribution |
⚠️ KPI口径注意:actual_profit 用 sum(e.actual_store_contribution),LEFT JOIN 费用表后无费用门店的 actual_store_contribution 为 NULL,sum(NULL) 忽略,所以实际只含有费用的门店。但 actual_revenue 用 sum(r.received) 包含全部94家。利润率分母含全部门店收入,分子仅含费用匹配门店利润,可能偏低。
区块②:利润结构(瀑布图)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
wf.consumption |
/overview/profit-waterfall |
consumption |
sum(consumption) FILTER(has_expense) |
bill_fact.consumption |
| 优惠 |
wf.discount |
同上 |
discount |
sum(discount) FILTER(has_expense) |
bill_fact.discount_total |
| 实收 |
wf.received |
同上 |
received |
sum(received) FILTER(has_expense) |
mv_store_risk_rating_monthly.received |
| 食材成本 |
wf.food_cost |
同上 |
food_cost |
sum(actual_food_cost) |
mv_store_operating_expense_monthly.actual_food_cost |
| 人工 |
wf.wage |
同上 |
wage |
sum(wage_expense) |
mv_store_operating_expense_monthly.wage_expense |
| 房租 |
wf.rent |
同上 |
rent |
sum(rent_expense) |
mv_store_operating_expense_monthly.rent_expense |
| 水电 |
wf.utility |
同上 |
utility |
sum(utility_expense) |
mv_store_operating_expense_monthly.utility_expense |
| 宿舍 |
wf.dorm |
同上 |
dorm |
sum(dorm_expense) |
mv_store_operating_expense_monthly.dorm_expense |
| 外卖佣金 |
wf.commission |
同上 |
commission |
sum(delivery_commission_expense) |
mv_store_operating_expense_monthly.delivery_commission_expense |
| 其他费用 |
wf.other_expense |
同上 |
other_expense |
sum(card_fee + repair_clean) |
mv_store_operating_expense_monthly.card_fee_expense + repair_clean_expense |
| 门店贡献利润 |
wf.store_contribution |
同上 |
store_contribution |
sum(received) FILTER(has_expense) - sum(food_cost) - sum(operating_expense) |
同上 |
| 食材成本率(占比条) |
前端计算 |
同上 |
前端除法 |
wf.food_cost / wf.received * 100 |
同上 |
| 人工费率(占比条) |
前端计算 |
同上 |
前端除法 |
wf.wage / wf.received * 100 |
同上 |
| 房租费率(占比条) |
前端计算 |
同上 |
前端除法 |
wf.rent / wf.received * 100 |
同上 |
| 水电费率(占比条) |
前端计算 |
同上 |
前端除法 |
wf.utility / wf.received * 100 |
同上 |
| 其他费率(占比条) |
前端计算 |
同上 |
前端除法 |
(dorm+commission+other) / wf.received * 100 |
同上 |
| 贡献率(占比条) |
前端计算 |
同上 |
前端除法 |
wf.store_contribution / wf.received * 100 |
同上 |
| 费用率(汇总) |
前端计算 |
同上 |
前端除法 |
wf.total_expense / wf.received * 100 |
同上 |
✅ 口径已修复:所有指标均基于 FILTER(has_expense) 的92家门店,与 store-expense/overview 一致。
区块②b:利润机会池
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 机会类别 |
o.category |
/overview/profit-opportunity |
items[].category |
5类: 食材成本差异/人工优化/水电节能/优惠管控/外卖佣金/SKU精简 |
多表 |
| 机会金额 |
o.opportunity |
同上 |
items[].opportunity |
各类不同公式,如食材=diff*30% |
mv_store_risk_rating_monthly + mv_store_operating_expense_monthly + mv_dish_sku_abc_monthly |
| 基线值 |
o.baseline |
同上 |
items[].baseline |
各类基线值 |
同上 |
| 信心度 |
o.confidence |
同上 |
items[].confidence |
中高/中/低 |
— |
| 责任方 |
o.owner |
同上 |
items[].owner |
静态文本 |
— |
| 验收标准 |
o.evidence |
同上 |
items[].evidence |
静态文本 |
— |
| 详情 |
o.detail |
同上 |
items[].detail |
动态拼接TOP5门店数据 |
同上 |
| 机会合计 |
totalOpportunity |
前端计算 |
— |
sum(items[].opportunity) |
同上 |
| 30天承诺值 |
静态文本 |
— |
— |
≥ 150万元(硬编码) |
— |
| 占比 |
pct |
前端计算 |
— |
opp / totalOpportunity * 100 |
同上 |
区块③:风险态势(3个卡片)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 红色门店数 |
riskSummary['红色'] |
/stores/risk |
risk_level count |
count(*) FILTER(risk_level='红色') |
mv_store_risk_rating_monthly.risk_level |
| 红色门店实收 |
riskRevSummary['红色'] |
同上 |
received sum |
sum(received) FILTER(risk_level='红色') |
mv_store_risk_rating_monthly.received |
| 红色实收占比 |
前端计算 |
同上 |
前端除法 |
riskRevSummary['红色'] / od.received * 100 |
同上 |
| 黄色门店数 |
riskSummary['黄色'] |
同上 |
同上 |
同上 |
同上 |
| 黄色门店实收 |
riskRevSummary['黄色'] |
同上 |
同上 |
同上 |
同上 |
| 黄色实收占比 |
前端计算 |
同上 |
前端除法 |
同上 |
同上 |
| 绿色门店数 |
riskSummary['绿色'] |
同上 |
同上 |
同上 |
同上 |
| 绿色门店实收 |
riskRevSummary['绿色'] |
同上 |
同上 |
同上 |
同上 |
| 绿色实收占比 |
前端计算 |
同上 |
前端除法 |
同上 |
同上 |
✅ 口径已修复:实收占比分母用 od.received(/overview API),与DashboardPage一致。
区块③b:重点整改门店清单
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 门店名 |
s.store_name |
/stores/priority |
store_name |
mv_store_action_priority_deep_monthly.store_name |
| 实收 |
s.received |
同上 |
received |
同上.received |
| 优先级 |
s.action_priority |
同上 |
action_priority |
同上.action_priority |
| 风险等级 |
s.risk_level |
同上 |
risk_level |
同上.risk_level |
| 问题组合 |
s.problem_combination |
同上 |
problem_combination |
同上.problem_combination |
区块④:成本异常分布
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 严重超耗门店数 |
costOv.red_count |
/cost-analysis/store-overview |
red_count |
count(*) FILTER(variance_level='红色-严重超耗') |
mv_store_theoretical_actual_cost_monthly.variance_level |
| 明显超耗门店数 |
costOv.orange_count |
同上 |
orange_count |
count(*) FILTER(variance_level='橙色-明显超耗') |
同上 |
| 基本正常门店数 |
costOv.green_count |
同上 |
green_count |
count(*) FILTER(variance_level='绿色-基本正常') |
同上 |
| 总差异金额 |
costOv.total_variance |
同上 |
total_variance |
sum(food_cost_variance) |
mv_store_theoretical_actual_cost_monthly.food_cost_variance |
区块④b:费用结构(饼图)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 费用科目名 |
r.account_name |
/store-expense/expense-structure |
account_name |
v_operating_expense_account_monthly.account_name |
| 费用金额 |
r.amount |
同上 |
amount |
v_operating_expense_account_monthly.amount |
| 费用占比 |
r.expense_share_pct |
同上 |
expense_share_pct |
v_operating_expense_account_monthly.expense_share_pct |
区块⑤:门店营收排名
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| TOP5门店名 |
r.store_name |
/stores/risk |
store_name |
前端按 received 降序取前5 |
mv_store_risk_rating_monthly |
| TOP5实收 |
r.received |
同上 |
received |
同上 |
mv_store_risk_rating_monthly.received |
| BOTTOM5门店名 |
同上 |
同上 |
同上 |
前端按 received 升序取末5(received>0) |
同上 |
| BOTTOM5实收 |
同上 |
同上 |
同上 |
同上 |
同上 |
区块⑤b:门店利润排名
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店名 |
s.store_name |
/overview/store-profit-ranking |
store_name |
— |
mv_store_risk_rating_monthly.store_name |
| 实收 |
s.received |
同上 |
received |
r.received |
mv_store_risk_rating_monthly.received |
| 贡献利润 |
s.store_contribution |
同上 |
store_contribution |
r.received - COALESCE(e.actual_food_cost,0) - COALESCE(e.operating_expense,0) |
同上 + mv_store_operating_expense_monthly |
| 贡献率 |
s.contribution_margin_pct |
同上 |
contribution_margin_pct |
store_contribution / received * 100 |
同上 |
⚠️ store-profit-ranking 口径注意:用 COALESCE(...,0) 处理无费用门店,2家无费用门店的贡献利润 = received - 0 - 0 = received(全部实收算作利润),这会导致排名中这2家门店排在最前面。与 store-expense/overview 的 actual_net_profit 口径不一致。
区块⑥:日度实收趋势
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 日度实收折线 |
dailyRows[].received |
/overview/daily |
received |
analytics.mv_overview_daily.received |
| 日期 |
dailyRows[].business_date |
同上 |
business_date |
analytics.mv_overview_daily.business_date |
| 环比上周% |
trendReceived |
前端计算 |
— |
(last7 - prev7) / prev7 * 100 |
区块⑦:本月经营态势弹窗(BusinessReportDialog)
该弹窗接收 BossPage 已加载的数据(od, ex, wf, riskRows, priorityRows, costOv, profitOpp, trendReceived)进行语音播报,不额外调用API。仅调用 /tts API进行语音合成。
五、页面3:门店工作台 StorePage
7个Tab + 概览折叠区。共调用13个API(含KPISection组件1个)。
概览折叠区(门店概况与经营概览)
门店概况(4个卡片)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店名称 |
storeName |
/stores/risk |
store_name |
— |
mv_store_risk_rating_monthly.store_name |
| 风险等级 |
storeInfo.risk |
同上 |
risk_level |
— |
mv_store_risk_rating_monthly.risk_level |
| 主要问题 |
primaryIssue |
/stores/priority |
problem_combination |
— |
mv_store_action_priority_deep_monthly.problem_combination |
| 任务完成率 |
前端计算 |
/tasks |
status count |
doneTasks / tasks * 100 |
analytics.store_task.status |
| 已完成/总数(描述) |
前端计算 |
同上 |
同上 |
doneTasks.length / tasks.length |
同上 |
KPI达成率(KPISection组件,level=store)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 收入达成率 |
kpi.revenue_achievement_pct |
/analytics-enhanced/kpi |
revenue_achievement_pct |
r.received / t.revenue_target * 100 |
mv_store_risk_rating_monthly.received + dim_store_target.revenue_target |
| 利润达成率 |
kpi.profit_achievement_pct |
同上 |
profit_achievement_pct |
e.actual_store_contribution / t.profit_target * 100 |
mv_store_operating_expense_monthly.actual_store_contribution + dim_store_target.profit_target |
| 目标收入 |
kpi.revenue_target |
同上 |
revenue_target |
t.revenue_target |
dim_store_target.revenue_target |
| 利润率 |
kpi.profit_margin_pct |
同上 |
profit_margin_pct |
e.actual_store_contribution / r.received * 100 |
同上 |
最新经营日概览(daily-card)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 营业收入(当日) |
item.value(metric=营业收入) |
/tasks/stores/:code/daily-card |
anomalies[].value |
sum(c009) 当日 |
bill_records.c009 |
| 营业收入基准 |
item.baseline |
同上 |
anomalies[].baseline |
sum(c009) 一周前同日 |
bill_records.c009 |
| 营业收入异常 |
item.is_anomaly |
同上 |
anomalies[].is_anomaly |
value < baseline * 0.8 |
— |
| 优惠(当日) |
item.value(metric=优惠) |
同上 |
同上 |
sum(c068) 当日 |
bill_records.c068 |
| 优惠异常 |
同上 |
同上 |
同上 |
value > baseline * 1.2 |
— |
| 实收(当日) |
item.value(metric=实收) |
同上 |
同上 |
sum(c114) 当日 |
bill_records.c114 |
| 实收异常 |
同上 |
同上 |
同上 |
value < baseline * 0.8 |
— |
| 账单数(当日) |
item.value(metric=账单数) |
同上 |
同上 |
count(*) 当日 |
bill_records |
| 账单数异常 |
同上 |
同上 |
同上 |
value < baseline * 0.8 |
— |
| 客单价(当日) |
item.value(metric=客单价) |
同上 |
同上 |
sum(c114)/count(*) 当日 |
bill_records |
| 客单价异常 |
同上 |
同上 |
同上 |
value < baseline * 0.9 |
— |
| 异常项数 |
anomalyCount |
前端计算 |
— |
count(is_anomaly=true) |
— |
| 对比日期 |
card.target_date / card.baseline_date |
同上 |
target_date / baseline_date |
max(c176::date) / target_date - 7天 |
bill_records.c176 |
本周指标进度(followup)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 实收(基线/目标/实际) |
followup.baseline_received / target_received / actual_received |
/tasks/followup |
同名 |
analytics.mv_store_monthly_followup |
| 客单价(基线/目标/实际) |
followup.baseline_avg_bill / target_avg_bill / actual_avg_bill |
同上 |
同名 |
同上 |
| 优惠率(基线/目标/实际) |
followup.baseline_discount_rate / target_discount_rate / actual_discount_rate |
同上 |
同名 |
同上 |
| 毛利率(基线/目标/实际) |
followup.baseline_margin_rate / target_margin_rate / actual_margin_rate |
同上 |
同名 |
同上 |
| 达成率 |
前端计算 |
— |
— |
actual / target * 100 |
| 异常率(基线/目标/实际) |
followup.baseline_anomaly_rate / target_anomaly_rate / actual_anomaly_rate |
同上 |
同名 |
同上 |
| 会员占比(基线/目标/实际) |
followup.baseline_member_share / target_member_share / actual_member_share |
同上 |
同名 |
同上 |
| 工作重点 |
followup.work_focus |
同上 |
work_focus |
同上 |
| 行动计划 |
followup.action_plan |
同上 |
action_plan |
同上 |
日度实收趋势
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 日度实收折线 |
dailyRows[].received |
/stores/:code/daily |
received |
bill_records.c114 (按c176::date分组) |
| 日期 |
dailyRows[].business_date |
同上 |
business_date |
bill_records.c176::date |
核心SKU备货提醒
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| SKU名称 |
s.dish_name |
/sku/abc |
dish_name |
analytics.mv_dish_sku_abc_monthly.dish_name |
| ABC等级 |
s.abc_class |
同上 |
abc_class |
同上.abc_class |
| 营收占比 |
s.revenue_share_pct |
同上 |
revenue_share_pct |
同上.revenue_share_pct |
| 累计占比 |
s.cumulative_revenue_share_pct |
同上 |
cumulative_revenue_share_pct |
同上.cumulative_revenue_share_pct |
前端过滤 abc_class === 'A' 取前10条。
待办/已完成任务
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 优先级 |
t.priority |
/tasks |
priority |
analytics.store_task.priority |
| 问题指标 |
t.problem_indicator |
同上 |
problem_indicator |
同上.problem_indicator |
| 状态 |
t.status |
同上 |
status |
同上.status |
| 行动要求 |
t.action_required |
同上 |
action_required |
同上.action_required |
| 截止日 |
t.deadline |
同上 |
deadline |
同上.deadline |
| 验收结果 |
t.verification_result |
同上 |
verification_result |
同上.verification_result |
| 执行证据 |
t.process_evidence |
同上 |
process_evidence |
同上.process_evidence |
| 后续计划 |
t.next_step |
同上 |
next_step |
同上.next_step |
核心指标行(8个MetricCard,scorecard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
sc.consumption |
/stores/:code |
scorecard.consumption |
sum(c009) |
bill_records.c009 |
| 优惠 |
sc.discount |
同上 |
scorecard.discount |
sum(c068) |
bill_records.c068 |
| 月度实收 |
sc.received |
同上 |
scorecard.received |
sum(c114) |
bill_records.c114 |
| 月度账单数 |
sc.bill_count |
同上 |
scorecard.bill_count |
count(*) |
bill_records |
| 客单价 |
sc.avg_bill_value |
同上 |
scorecard.avg_bill_value |
sum(c114)/count(*) |
bill_records |
| 优惠率 |
sc.discount_rate_pct |
同上 |
scorecard.discount_rate_pct |
sum(c068)/sum(c009)*100 |
bill_records |
| 理论毛利率 |
sc.theoretical_margin_pct |
同上 |
scorecard.theoretical_margin_pct |
sum(c181)/sum(c114)*100 |
bill_records.c181/c114 |
| 会员占比 |
sc.member_bill_share_pct |
同上 |
scorecard.member_bill_share_pct |
count(c185非空)/count(*)*100 |
bill_records.c185 |
⚠️ scorecard数据源注意:/stores/:code 的 scorecard 直接从 bill_records 原始表查询(非物化视图),而其他页面用 mv_store_risk_rating_monthly。两表同月数据应一致,但若刷新不及时可能存在差异。
风险与经营状态说明
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 风险等级 |
risk.risk_level |
/stores/:code |
risk.risk_level |
mv_store_risk_rating_monthly.risk_level |
| 问题组合 |
action.problem_combination |
同上 |
action.problem_combination |
mv_store_action_priority_deep_monthly.problem_combination |
| 经营象限 |
action.management_quadrant |
同上 |
action.management_quadrant |
后端计算:日均营收 vs 中位18642 & 毛利率 vs 中位70% |
| 规模层级 |
action.scale_tier |
同上 |
action.scale_tier |
mv_store_action_priority_deep_monthly.scale_tier |
| 综合基准分 |
action.benchmark_score |
同上 |
benchmark.benchmark_score |
mv_store_benchmark_composite_monthly |
| 行动优先级 |
action.action_priority |
同上 |
action.action_priority |
mv_store_action_priority_deep_monthly.action_priority |
| 成本差异率 |
action.variance_to_theoretical_pct |
同上 |
action.variance_to_theoretical_pct |
同上.variance_to_theoretical_pct |
| 成本差异等级 |
action.variance_level |
同上 |
action.variance_level |
同上.variance_level |
月度指标偏差对比(vs 公司均值,硬编码)
| 显示指标 |
前端变量 |
门店值来源 |
公司均值 |
数据源表 |
| 日均营收 |
risk.avg_daily_received |
/stores/:code → risk |
20144(硬编码) |
mv_store_risk_rating_monthly.avg_daily_received |
| 客单价 |
risk.avg_bill_value |
同上 |
36.8(硬编码) |
同上.avg_bill_value |
| 优惠率 |
risk.discount_rate_pct |
同上 |
20.5(硬编码) |
同上.discount_rate_pct |
| 毛利率 |
risk.theoretical_margin_pct |
同上 |
71.5(硬编码) |
同上.theoretical_margin_pct |
| 会员占比 |
risk.member_bill_share_pct |
同上 |
15.9(硬编码) |
同上.member_bill_share_pct |
| 复购率 |
action.repeat_rate_pct |
同上 → action |
37.0(硬编码) |
mv_store_action_priority_deep_monthly.repeat_rate_pct |
| 外卖占比 |
action.delivery_bill_share_pct |
同上 |
36.1(硬编码) |
同上.delivery_bill_share_pct |
| 成本差异率 |
action.variance_to_theoretical_pct |
同上 |
20(硬编码) |
同上.variance_to_theoretical_pct |
⚠️ 公司均值硬编码:companyAvg 对象中的值是硬编码的,不随数据更新而变化。如果实际公司均值发生变化,偏差对比将不准确。
Tab1:概览
健康度评分维度(雷达图 + 进度条)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 健康总分 |
health.health_score |
/situational-awareness/health-score |
health_score |
8维加权总分(0-100) |
多表联合计算 |
| 营收规模得分 |
health.score_revenue |
同上 |
score_revenue |
20 * LEAST(1.0, avg_daily_received/30000) |
mv_store_risk_rating_monthly.avg_daily_received |
| 成本控制得分 |
health.score_cost |
同上 |
score_cost |
20 * GREATEST(0, 1 - LEAST(variance,50)/50) |
mv_store_theoretical_actual_cost_monthly.variance_to_theoretical_pct |
| 毛利率得分 |
health.score_margin |
同上 |
score_margin |
15 * LEAST(1.0, GREATEST(0, margin-60)/15) |
mv_store_risk_rating_monthly.theoretical_margin_pct |
| 风险控制得分 |
health.score_risk |
同上 |
score_risk |
绿色=10, 黄色=6, 红色=2 |
mv_store_risk_rating_monthly.risk_level |
| 复购率得分 |
health.score_repeat |
同上 |
score_repeat |
10 * LEAST(1.0, repeat_rate/40) |
mv_store_repeat_summary_monthly.repeat_rate_pct |
| 会员占比得分 |
health.score_member |
同上 |
score_member |
10 * LEAST(1.0, member_share/20) |
mv_store_risk_rating_monthly.member_bill_share_pct |
| 任务完成得分 |
health.score_task |
同上 |
score_task |
10 * completion_rate/100 |
analytics.store_task |
| 客单价得分 |
health.score_bill |
同上 |
score_bill |
5 * LEAST(1.0, avg_bill_value/40) |
mv_store_risk_rating_monthly.avg_bill_value |
| 健康状态 |
health.health_status |
同上 |
health_status |
≥75=健康, ≥55=亚健康, <55=需干预 |
— |
平台经济性
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 美团实收 |
sd.platform.meituan_received |
/stores/:code |
platform.meituan_received |
mv_store_platform_economics_monthly.meituan_received |
| 饿了么实收 |
sd.platform.eleme_received |
同上 |
platform.eleme_received |
同上.eleme_received |
| 抖音实收 |
sd.platform.douyin_received |
同上 |
platform.douyin_received |
同上.douyin_received |
| 平台加权成本率 |
sd.platform.weighted_cost_rate_pct |
同上 |
platform.weighted_cost_rate_pct |
同上.weighted_cost_rate_pct |
Tab2:餐段分析
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 餐段 |
mealRows[].meal_period |
/stores/:code/meal-period |
meal_period |
— |
analytics.bill_fact.meal_period |
| 账单数 |
mealRows[].bill_count |
同上 |
bill_count |
count(*) |
analytics.bill_fact |
| 实收 |
mealRows[].received |
同上 |
received |
sum(received_total) |
analytics.bill_fact.received_total |
| 平均单价 |
mealRows[].avg_bill |
同上 |
avg_bill |
sum(received_total)/count(*) |
同上 |
| 全网均价 |
mealRows[].network_avg_bill |
同上 |
network_avg_bill |
全门店同餐段 sum(received)/count(*) |
analytics.bill_fact |
| vs全网% |
mealRows[].vs_network_pct |
同上 |
vs_network_pct |
(store.avg / network.avg - 1) * 100 |
— |
Tab3:品类结构
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店各品类金额 |
s.lanzhou_noodle 等 |
/stores/:code/category-mix |
store.* |
各品类 sum(consumption) |
mv_store_category_mix_monthly |
| 公司各品类金额 |
c.total_noodle 等 |
同上 |
company.* |
全门店 sum(各品类) |
同上 |
| 门店品类占比 |
前端计算 |
— |
— |
品类金额 / 门店总金额 * 100 |
— |
| 公司品类占比 |
前端计算 |
— |
— |
品类金额 / 公司总金额 * 100 |
— |
| 主力品类 |
s.top_category |
同上 |
store.top_category |
— |
mv_store_category_mix_monthly.top_category |
| 主力品类占比 |
s.top_category_share_pct |
同上 |
store.top_category_share_pct |
— |
同上.top_category_share_pct |
| 面食占比 |
s.noodle_share_pct |
同上 |
store.noodle_share_pct |
— |
同上.noodle_share_pct |
| 外卖占比 |
s.delivery_package_share_pct |
同上 |
store.delivery_package_share_pct |
— |
同上.delivery_package_share_pct |
Tab4:成本分析
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 理论成本率 |
cost.cost.theoretical_cost_rate_pct |
/stores/:code/cost |
cost.theoretical_cost_rate_pct |
— |
mv_store_theoretical_actual_cost_monthly |
| 实际成本率 |
cost.cost.actual_food_cost_rate_pct |
同上 |
cost.actual_food_cost_rate_pct |
— |
同上 |
| 差异率 |
cost.cost.variance_to_theoretical_pct |
同上 |
cost.variance_to_theoretical_pct |
— |
同上 |
| 差异等级 |
cost.cost.variance_level |
同上 |
cost.variance_level |
— |
同上 |
| 原料分类名 |
cost.categories[].category_name |
同上 |
categories[].category_name |
finance_category |
mv_inventory_cost_classified_monthly.finance_category |
| 消耗金额 |
cost.categories[].consumption_amount |
同上 |
categories[].consumption_amount |
sum(consumption_amount) |
同上.consumption_amount |
| 实际占比 |
cost.categories[].actual_cost_rate_pct |
同上 |
categories[].actual_cost_rate_pct |
分类消耗/总消耗*100 |
— |
| 公司基准 |
cost.categories[].benchmark_rate_pct |
同上 |
categories[].benchmark_rate_pct |
全门店同分类占比 |
— |
| 差异 |
cost.categories[].variance_pct |
同上 |
categories[].variance_pct |
actual - benchmark |
— |
Tab5:会员分析
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 会员占比 |
member.opportunity.member_share_pct |
/stores/:code/member |
opportunity.member_share_pct |
— |
mv_store_member_opportunity_monthly |
| 公司均值会员占比 |
member.opportunity.company_member_share_pct |
同上 |
opportunity.company_member_share_pct |
— |
同上 |
| 复购率 |
member.repeat.repeat_rate_pct |
同上 |
repeat.repeat_rate_pct |
— |
mv_store_repeat_summary_monthly |
| 复购收入占比 |
member.repeat.repeat_revenue_share_pct |
同上 |
repeat.repeat_revenue_share_pct |
— |
同上 |
| 活跃会员数 |
member.monthly.member_count |
同上 |
monthly.member_count |
count(*) |
v_store_member_monthly_activity |
| 总订单数 |
member.monthly.total_orders |
同上 |
monthly.total_orders |
sum(orders) |
同上 |
| 人均订单 |
member.monthly.avg_orders |
同上 |
monthly.avg_orders |
avg(orders) |
同上 |
| 人均消费 |
member.monthly.avg_received |
同上 |
monthly.avg_received |
avg(received) |
同上 |
| 提升机会(文本) |
member.opportunity.conversion_bill_scenario |
同上 |
opportunity.conversion_bill_scenario |
— |
mv_store_member_opportunity_monthly |
| 收入提升场景(文本) |
member.opportunity.revenue_uplift_scenario |
同上 |
opportunity.revenue_uplift_scenario |
— |
同上 |
Tab6:异常账单
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 账单号 |
r.bill_no |
/stores/:code/anomalies |
bill_no |
mv_risk_anomaly.bill_no |
| 餐段 |
r.meal_period |
同上 |
meal_period |
同上.meal_period |
| 消费额 |
r.consumption |
同上 |
consumption |
同上.consumption |
| 优惠 |
r.discount_total |
同上 |
discount_total |
同上.discount_total |
| 实收 |
r.received_total |
同上 |
received_total |
同上.received_total |
| 异常原因 |
r.anomaly_reason |
同上 |
anomaly_reason |
同上.anomaly_reason |
| 结账时间 |
r.closed_at |
同上 |
closed_at |
同上.closed_at |
| 总数 |
anomalyDetailTotal |
同上 |
meta.total |
— |
⚠️ anomalies数据源注意:/stores/:code/anomalies 通过 store_name(非 store_code)关联 mv_risk_anomaly 视图,需先查 dim_store 获取 store_name 再查异常表。
Tab7:人力排班
人力成本概览(6个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 人工成本 |
staffing.summary.wage_expense |
/stores/:code/staffing |
summary.wage_expense |
— |
mv_store_operating_expense_monthly.wage_expense |
| 人工成本率 |
staffing.summary.wage_rate_pct |
同上 |
summary.wage_rate_pct |
— |
同上.wage_rate_pct |
| 公司均值人工率 |
staffing.summary.avg_wage_rate |
同上 |
summary.avg_wage_rate |
avg(wage_rate_pct) 排除>100% |
同上 |
| 人效 |
staffing.summary.revenue_per_wage |
同上 |
summary.revenue_per_wage |
received / wage_expense |
同上 |
| 每单人工成本 |
staffing.summary.wage_per_bill |
同上 |
summary.wage_per_bill |
wage_expense / bill_count |
同上 |
| 公司均值人效 |
staffing.summary.avg_rev_per_wage |
同上 |
summary.avg_rev_per_wage |
avg(received/wage_expense) |
同上 |
人力成本优化空间
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 建议人工成本 |
staffing.summary.suggested_wage |
同上 |
summary.suggested_wage |
received * max(20%, avgWageRate-3%) / 100 |
后端计算 |
| 可节省金额 |
staffing.summary.wage_savings |
同上 |
summary.wage_savings |
wage_expense - suggested_wage |
后端计算 |
| 节省比例 |
staffing.summary.savings_pct |
同上 |
summary.savings_pct |
wage_savings / wage_expense * 100 |
后端计算 |
按星期排班分析
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 星期 |
weekdays[].weekday |
同上 |
weekdays[].weekday |
— |
v_store_daily |
| 日均实收 |
weekdays[].avg_received |
同上 |
同上 |
avg(received) 按星期分组 |
v_store_daily.received |
| 日均账单 |
weekdays[].avg_bills |
同上 |
同上 |
avg(bill_count) |
v_store_daily.bill_count |
| 最高实收 |
weekdays[].max_received |
同上 |
同上 |
max(received) |
v_store_daily.received |
| 最低实收 |
weekdays[].min_received |
同上 |
同上 |
min(received) |
v_store_daily.received |
| 建议排班比 |
weekdays[].suggested_headcount_ratio |
同上 |
同上 |
avg_received / 全周日均 * 100 |
后端计算 |
| 排班等级 |
weekdays[].staffing_level |
同上 |
同上 |
>110%=高峰, <85%=低谷, else=正常 |
— |
| 排班建议 |
weekdays[].staffing_action |
同上 |
同上 |
静态文本 |
— |
餐段排班分析
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 餐段 |
meals[].meal_period |
同上 |
meals[].meal_period |
— |
v_store_meal_opportunity |
| 账单数 |
meals[].bill_count |
同上 |
同上 |
— |
同上 |
| 实收 |
meals[].received |
同上 |
同上 |
— |
同上 |
| 客单价 |
meals[].avg_bill |
同上 |
同上 |
— |
同上 |
| 账单占比 |
meals[].bill_share_pct |
同上 |
同上 |
餐段账单/总账单*100 |
后端计算 |
| 排班等级 |
meals[].staffing_level |
同上 |
同上 |
>40%=主力, >20%=次高峰, >5%=辅助, else=低谷 |
— |
| 排班建议 |
meals[].staffing_action |
同上 |
同上 |
静态文本 |
— |
日营收明细(排班参考)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 日期 |
daily[].business_date |
同上 |
daily[].business_date |
v_store_daily.business_date |
| 实收 |
daily[].received |
同上 |
同上 |
v_store_daily.received |
六、页面4:菜品成本 CostAnalysisPage
10个Tab,每个Tab独立组件。共调用22个API(含1个POST、1个PUT)。
核心数据源:public.dish_cost_analysis_summary(菜品成本汇总表,按月导入)+ public.dish_cost_analysis_material_detail(原料明细表)+ analytics.fact_recipe_bom(BOM配方表)。
Tab1:成本总览(OverviewTab)
概览指标(8个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 总销售额 |
ov.total_sales |
/cost-analysis/overview |
total_sales |
sum(sales_amount) |
dish_cost_analysis_summary.sales_amount |
| 理论成本合计 |
ov.total_theo_cost |
同上 |
total_theo_cost |
sum(theoretical_cost) |
同上.theoretical_cost |
| 实际成本合计 |
ov.total_actual_cost |
同上 |
total_actual_cost |
sum(actual_cost) |
同上.actual_cost |
| 成本差异 |
ov.total_variance |
同上 |
total_variance |
sum(cost_variance_amount) |
同上.cost_variance_amount |
| 平均理论毛利率 |
ov.avg_theo_margin |
同上 |
avg_theo_margin |
(1 - sum(theoretical_cost)/sum(sales_amount)) * 100 |
同上 |
| 平均实际毛利率 |
ov.avg_actual_margin |
同上 |
avg_actual_margin |
(1 - sum(actual_cost)/sum(sales_amount)) * 100 |
同上 |
| 低毛利菜品数 |
ov.low_margin_dishes |
同上 |
low_margin_dishes |
count(*) FILTER(theoretical_margin_rate_pct < 50) |
同上.theoretical_margin_rate_pct |
| 超理论菜品数 |
ov.over_cost_dishes |
同上 |
over_cost_dishes |
count(*) FILTER(cost_variance_amount > 0) |
同上.cost_variance_amount |
数据导入机制:所有查询通过 import_id 关联 dish_cost_analysis_import_log 取最新月度导入批次。
品类成本对比
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 品类 |
cats[].category_level1 |
/cost-analysis/category-comparison |
category_level1 |
— |
dish_cost_analysis_summary.category_level1 |
| 菜品数 |
cats[].dishes |
同上 |
dishes |
count(*) |
同上 |
| 理论毛利率 |
cats[].avg_theo_margin |
同上 |
avg_theo_margin |
(1 - sum(theoretical_cost)/sum(sales_amount)) * 100 |
同上 |
| 实际毛利率 |
cats[].avg_actual_margin |
同上 |
avg_actual_margin |
(1 - sum(actual_cost)/sum(sales_amount)) * 100 |
同上 |
| 销售额 |
cats[].total_sales |
同上 |
total_sales |
sum(sales_amount) |
同上 |
| 成本差异 |
cats[].total_variance |
同上 |
total_variance |
sum(cost_variance_amount) |
同上 |
毛利率偏差分布
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 偏差区间 |
devs[].deviation_band |
/cost-analysis/margin-deviation |
deviation_band |
CASE分组:实际-理论偏差 |
dish_cost_analysis_summary |
| 菜品数 |
devs[].cnt |
同上 |
cnt |
count(*) |
同上 |
成本差异TOP榜
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
tops[].dish_name |
/cost-analysis/variance-top |
dish_name |
— |
dish_cost_analysis_summary.dish_name |
| 品类 |
tops[].category_level1 |
同上 |
category_level1 |
— |
同上 |
| 理论毛利率 |
tops[].theo_margin |
同上 |
theo_margin |
theoretical_margin_rate_pct |
同上 |
| 实际毛利率 |
tops[].actual_margin |
同上 |
actual_margin |
actual_margin_rate_pct |
同上 |
| 成本差异 |
tops[].cost_variance |
同上 |
cost_variance |
cost_variance_amount |
同上 |
| 销售额 |
tops[].sales_amount |
同上 |
sales_amount |
— |
同上 |
| 分层 |
tops[].cost_tier |
同上 |
cost_tier |
CASE:>20%=紧急, >10%=整改, >0=关注, else=正常 |
— |
Tab2:菜品盈利(ProfitabilityTab)
菜单工程矩阵(散点图)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
matrixData[].dish_name |
/cost-analysis/menu-engineering |
dish_name |
— |
dish_cost_analysis_summary |
| 销量 |
matrixData[].sales_quantity |
同上 |
sales_quantity |
— |
同上.sales_quantity |
| 实际毛利率 |
matrixData[].actual_margin |
同上 |
actual_margin |
actual_margin_rate_pct |
同上 |
| 销售额 |
matrixData[].sales_amount |
同上 |
sales_amount |
— |
同上 |
| 菜单类型 |
matrixData[].menu_type |
同上 |
menu_type |
双中位分割:销量&毛利率各取中位数 → 明星/高销低利/低销高利/低销低利/数据异常 |
— |
菜品盈利明细(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
profitData[].dish_name |
/cost-analysis/profitability |
dish_name |
— |
dish_cost_analysis_summary |
| 品类 |
profitData[].category_level1 |
同上 |
category_level1 |
— |
同上 |
| 销量 |
profitData[].sales_quantity |
同上 |
sales_quantity |
— |
同上 |
| 销售额 |
profitData[].sales_amount |
同上 |
sales_amount |
— |
同上 |
| 理论毛利 |
profitData[].theo_profit |
同上 |
theo_profit |
sales_amount - theoretical_cost |
同上 |
| 实际毛利 |
profitData[].actual_profit |
同上 |
actual_profit |
sales_amount - actual_cost |
同上 |
| 理论毛利率 |
profitData[].theo_margin |
同上 |
theo_margin |
theoretical_margin_rate_pct |
同上 |
| 实际毛利率 |
profitData[].actual_margin |
同上 |
actual_margin |
actual_margin_rate_pct |
同上 |
| 收入贡献度 |
profitData[].revenue_contribution |
同上 |
revenue_contribution |
sales_amount / sum(sales_amount) OVER() * 100 |
同上 |
低毛利菜品预警
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
pricingData[].dish_name |
/cost-analysis/pricing |
dish_name |
— |
dish_cost_analysis_summary |
| 售价 |
pricingData[].price |
同上 |
price |
— |
同上.price |
| 理论成本 |
pricingData[].theo_cost |
同上 |
theo_cost |
theoretical_cost |
同上 |
| 理论成本率 |
pricingData[].theo_cost_rate |
同上 |
theo_cost_rate |
theoretical_cost / price * 100 |
同上 |
| 理论毛利率 |
pricingData[].theo_margin |
同上 |
theo_margin |
theoretical_margin_rate_pct |
同上 |
| 实际毛利率 |
pricingData[].actual_margin |
同上 |
actual_margin |
actual_margin_rate_pct |
同上 |
| 销售额 |
pricingData[].sales_amount |
同上 |
sales_amount |
— |
同上 |
筛选条件:theoretical_margin_rate_pct < 50 AND sales_amount > 1000。
Tab3:原料差异(MaterialTab)
菜品原料差异分解(按菜品编码查询)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 原料 |
varianceData[].material_name |
/cost-analysis/material-variance |
material_name |
— |
dish_cost_analysis_material_detail.material_name |
| 单位 |
varianceData[].material_unit |
同上 |
material_unit |
— |
同上.material_unit |
| 理论用量 |
varianceData[].theo_qty |
同上 |
theo_qty |
theoretical_quantity |
同上.theoretical_quantity |
| 实际用量 |
varianceData[].actual_qty |
同上 |
actual_qty |
actual_quantity |
同上.actual_quantity |
| 数量差异 |
varianceData[].loss_qty |
同上 |
loss_qty |
loss_quantity |
同上.loss_quantity |
| 损耗率 |
varianceData[].loss_rate |
同上 |
loss_rate |
loss_quantity_rate_pct |
同上.loss_quantity_rate_pct |
| 金额差异 |
varianceData[].loss_amount |
同上 |
loss_amount |
loss_amount |
同上.loss_amount |
| 原因 |
varianceData[].reason |
同上 |
reason |
CASE:<-100%=分摊遗漏, <-30%=份量超标, =0=未使用, else=正常损耗 |
— |
物料损耗率分布
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 损耗区间 |
distData[].loss_band |
/cost-analysis/loss-distribution |
loss_band |
CASE分档:无损耗/轻微/轻度/中度/严重/极重/正向 |
dish_cost_analysis_material_detail |
| 明细数 |
distData[].cnt |
同上 |
cnt |
count(*) |
同上 |
超耗物料TOP榜
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料 |
topData[].material_name |
/cost-analysis/material-loss-top |
material_name |
— |
dish_cost_analysis_material_detail |
| 类型 |
topData[].material_type |
同上 |
material_type |
— |
同上 |
| 涉及菜品数 |
topData[].dish_count |
同上 |
dish_count |
count(DISTINCT summary_id) |
同上 |
| 总损耗量 |
topData[].total_loss_qty |
同上 |
total_loss_qty |
sum(loss_quantity) |
同上 |
| 平均损耗率 |
topData[].avg_loss_rate |
同上 |
avg_loss_rate |
sum(loss_quantity)/sum(theoretical_quantity)*100 |
同上 |
| 最大损耗率 |
topData[].max_loss_rate |
同上 |
max_loss_rate |
max(loss_quantity_rate_pct) |
同上 |
| 损耗金额 |
topData[].total_loss_amount |
同上 |
total_loss_amount |
sum(loss_amount) |
同上 |
物料类型损耗对比
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料类型 |
typeData[].material_type |
/cost-analysis/material-type-loss |
material_type |
— |
dish_cost_analysis_material_detail |
| 明细数 |
typeData[].cnt |
同上 |
cnt |
count(*) |
同上 |
| 物料种类 |
typeData[].unique_materials |
同上 |
unique_materials |
count(DISTINCT material_name) |
同上 |
| 平均损耗率 |
typeData[].avg_loss_rate |
同上 |
avg_loss_rate |
sum(loss_quantity)/sum(theoretical_quantity)*100 |
同上 |
| 损耗金额 |
typeData[].total_loss_amount |
同上 |
total_loss_amount |
sum(loss_amount) |
同上 |
Tab4:BOM与配方(BomTab)
BOM总览(6个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| BOM覆盖率 |
ov.coverage_pct |
/cost-analysis/bom-overview |
coverage_pct |
count(DISTINCT sku_code in BOM) / count(dim_sku) * 100 |
fact_recipe_bom + dim_sku |
| 有BOM的SKU |
ov.sku_with_bom |
同上 |
sku_with_bom |
count(DISTINCT sku_code) |
fact_recipe_bom.sku_code |
| 缺BOM的SKU |
ov.sku_without_bom |
同上 |
sku_without_bom |
total_sku - sku_with_bom |
dim_sku - fact_recipe_bom |
| BOM总行数 |
ov.total_bom_rows |
同上 |
total_bom_rows |
count(*) |
fact_recipe_bom |
| 高损耗BOM数 |
ov.high_loss_bom |
同上 |
high_loss_bom |
count(*) FILTER(waste_rate > 20) |
fact_recipe_bom.waste_rate |
| 平均物料数/SKU |
ov.avg_materials_per_sku |
同上 |
avg_materials_per_sku |
avg(count per sku) |
同上 |
⚠️ bom-overview 无月份参数:该API不接收month参数,BOM数据不按月区分。
BOM复杂度明细(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| SKU编码 |
compData[].sku_code |
/cost-analysis/bom-complexity |
sku_code |
— |
fact_recipe_bom.sku_code |
| 菜品名 |
compData[].dish_name |
同上 |
dish_name |
dim_sku.standard_name |
dim_sku.standard_name |
| 品类 |
compData[].category_l1 |
同上 |
category_l1 |
— |
dim_sku.category_l1 |
| 原料数 |
compData[].material_count |
同上 |
material_count |
count(*) |
fact_recipe_bom |
| 半成品数 |
compData[].semi_finished_count |
同上 |
semi_finished_count |
count(*) FILTER(major_category='半成品') |
fact_recipe_bom + dim_material |
| 独有原料 |
compData[].unique_material_count |
同上 |
unique_material_count |
count(*) FILTER(ref_count=1) |
fact_recipe_bom(子查询ref_count) |
| 高损耗原料 |
compData[].high_loss_count |
同上 |
high_loss_count |
count(*) FILTER(waste_rate > 20) |
fact_recipe_bom.waste_rate |
| 复杂度 |
compData[].complexity_level |
同上 |
complexity_level |
CASE:≤5=低, ≤10=正常, ≤15=较复杂, >15=重点评审 |
— |
菜品物料构成(按SKU查询)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料 |
compDetail[].material_name |
/cost-analysis/bom-composition |
material_name |
— |
dim_material.material_name |
| 类型 |
compDetail[].material_type |
同上 |
material_type |
dim_material.major_category |
dim_material.major_category |
| 标准毛用量 |
compDetail[].gross_qty |
同上 |
gross_qty |
standard_gross_quantity |
fact_recipe_bom.standard_gross_quantity |
| 标准净用量 |
compDetail[].net_qty |
同上 |
net_qty |
standard_net_quantity |
fact_recipe_bom.standard_net_quantity |
| 损耗率 |
compDetail[].waste_rate |
同上 |
waste_rate |
— |
fact_recipe_bom.waste_rate |
| 成本占比 |
compDetail[].cost_share |
同上 |
cost_share |
theoretical_amount / sum(theoretical_amount) OVER(PARTITION BY summary_id) * 100 |
dish_cost_analysis_material_detail |
高损耗BOM预警
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
lossData[].dish_name |
/cost-analysis/bom-high-loss |
dish_name |
dim_sku.standard_name |
dim_sku |
| 物料 |
lossData[].material_name |
同上 |
material_name |
— |
dim_material |
| 损耗率 |
lossData[].waste_rate |
同上 |
waste_rate |
— |
fact_recipe_bom.waste_rate |
| 出成率 |
lossData[].yield_rate |
同上 |
yield_rate |
— |
fact_recipe_bom.yield_rate |
| 预警级别 |
lossData[].alert_level |
同上 |
alert_level |
CASE:>100%=极端, >50%=严重, else=关注 |
— |
筛选条件:waste_rate >= 20。无月份参数。
缺BOM的SKU清单(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| SKU编码 |
missData[].sku_code |
/cost-analysis/bom-missing |
sku_code |
— |
dim_sku.sku_code |
| 菜品名 |
missData[].dish_name |
同上 |
dish_name |
standard_name |
dim_sku.standard_name |
| 品类 |
missData[].category_l1 |
同上 |
category_l1 |
— |
dim_sku.category_l1 |
| 销售额 |
missData[].sales_amount |
同上 |
sales_amount |
COALESCE(dish_cost_analysis_summary.sales_amount, 0) |
dish_cost_analysis_summary |
| 销量 |
missData[].sales_quantity |
同上 |
sales_quantity |
COALESCE(dish_cost_analysis_summary.sales_quantity, 0) |
同上 |
筛选条件:sku_code NOT IN (SELECT DISTINCT sku_code FROM fact_recipe_bom)。
Tab5:供应链与精简(SupplyTab)
原料共用度
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料 |
sharingData[].material_name |
/cost-analysis/material-sharing |
material_name |
— |
dim_material.material_name |
| 类型 |
sharingData[].major_category |
同上 |
major_category |
— |
dim_material.major_category |
| 被引用SKU数 |
sharingData[].sku_count |
同上 |
sku_count |
count(DISTINCT sku_code) |
fact_recipe_bom.sku_code |
| 分类 |
sharingData[].sharing_type |
同上 |
sharing_type |
CASE:>50=核心原料, =1=独有原料, else=普通共用 |
— |
独有原料风险(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| SKU编码 |
riskData[].sku_code |
/cost-analysis/unique-material-risk |
sku_code |
— |
fact_recipe_bom |
| 菜品名 |
riskData[].dish_name |
同上 |
dish_name |
dim_sku.standard_name |
dim_sku |
| 品类 |
riskData[].category_l1 |
同上 |
category_l1 |
— |
dim_sku |
| 销售额 |
riskData[].sales_amount |
同上 |
sales_amount |
COALESCE(dish_cost_analysis_summary.sales_amount, 0) |
dish_cost_analysis_summary |
| 独有原料数 |
riskData[].unique_material_count |
同上 |
unique_material_count |
count(*) where ref_count=1 |
fact_recipe_bom |
| 风险等级 |
riskData[].risk_level |
同上 |
risk_level |
CASE:sales<5000 & count>3=高, sales<5000=中, else=低 |
— |
SKU精简模拟器(POST)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 收入影响 |
simResult.summary.revenue_impact |
POST /cost-analysis/sku-simplify-simulate |
summary.revenue_impact |
sum(sales_amount) for target SKUs |
dish_cost_analysis_summary |
| 毛利影响 |
simResult.summary.profit_impact |
同上 |
summary.profit_impact |
sum(sales_amount - actual_cost) |
同上 |
| 可减少原料数 |
simResult.summary.releasable_materials |
同上 |
summary.releasable_materials |
count(DISTINCT material_code) 独有原料 |
fact_recipe_bom |
| 仍需采购的共用原料 |
simResult.summary.shared_materials |
同上 |
summary.shared_materials |
count(DISTINCT material_code) 共用原料 |
同上 |
| 负毛利菜品数 |
simResult.summary.negative_margin_count |
同上 |
summary.negative_margin_count |
count(*) where actual_margin_rate_pct < 0 |
dish_cost_analysis_summary |
| 可释放物料 |
simResult.releasable_materials |
同上 |
releasable_materials |
独有物料明细 |
fact_recipe_bom + dim_material |
| 库存金额 |
releasable_materials[].inventory_value |
同上 |
inventory_value |
sum(actual_amount) |
dish_cost_analysis_material_detail |
BOM驱动物料需求预测
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料 |
rawDemandData[].material_name |
/cost-analysis/material-demand |
material_name |
— |
dim_material |
| 类型 |
rawDemandData[].major_category |
同上 |
major_category |
— |
dim_material.major_category |
| 单位 |
rawDemandData[].base_unit |
同上 |
base_unit |
— |
dim_material.base_unit |
| 预计需求量 |
rawDemandData[].estimated_demand |
同上 |
estimated_demand |
sum(standard_gross_quantity * sales_quantity) |
fact_recipe_bom × dish_cost_analysis_summary |
| 涉及菜品数 |
rawDemandData[].dish_count |
同上 |
dish_count |
count(DISTINCT sku_code) |
fact_recipe_bom |
Tab6:包装耗材(PackagingTab)
包装总览(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 包装物料种类 |
ovData.packaging_types |
/cost-analysis/packaging-overview |
packaging_types |
count(DISTINCT material_name) |
dish_cost_analysis_material_detail |
| 包装总成本 |
ovData.total_cost |
同上 |
total_cost |
sum(theoretical_amount) |
同上.theoretical_amount |
| 总损耗量 |
ovData.total_loss_qty |
同上 |
total_loss_qty |
sum(loss_quantity) |
同上.loss_quantity |
| 高损耗包装数 |
ovData.high_loss_count |
同上 |
high_loss_count |
count(*) FILTER(loss_rate < -20%) |
同上 |
筛选条件:material_name ~* '餐盒|餐具|打包|纸巾|碗|袋|杯|盒'(正则匹配包装物料名称)。
包装物料明细(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 物料 |
detailData[].material_name |
/cost-analysis/packaging-detail |
material_name |
— |
dish_cost_analysis_material_detail |
| 涉及菜品数 |
detailData[].dish_count |
同上 |
dish_count |
count(DISTINCT summary_id) |
同上 |
| 总用量 |
detailData[].total_qty |
同上 |
total_qty |
sum(theoretical_quantity) |
同上 |
| 总成本 |
detailData[].total_cost |
同上 |
total_cost |
sum(theoretical_amount) |
同上 |
| 损耗量 |
detailData[].loss_qty |
同上 |
loss_qty |
sum(loss_quantity) |
同上 |
| 平均损耗率 |
detailData[].avg_loss_rate |
同上 |
avg_loss_rate |
sum(loss_quantity)/sum(theoretical_quantity)*100 |
同上 |
| 状态 |
detailData[].status |
同上 |
status |
CASE:<-20%=核查, <-5%=关注, else=正常 |
— |
Tab7:数据质量(QualityTab)
数据质量总览(3个MetricCard + 6项检查)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| BOM覆盖率 |
ovData.bom_coverage |
/cost-analysis/data-quality |
bom_coverage |
count(DISTINCT sku_code in BOM) / count(dim_sku) * 100 |
fact_recipe_bom + dim_sku |
| 菜品匹配率 |
前端计算 |
同上 |
matched_dishes / total_dishes |
matched_dishes / total_dishes * 100 |
dish_cost_analysis_summary + dish_sales_details |
| 物料匹配率 |
前端计算 |
同上 |
matched_materials / total_materials |
matched_materials / total_materials * 100 |
dish_cost_analysis_material_detail + inventory_cost_records |
| 零实际用量BOM |
ovData.zero_actual_bom |
同上 |
zero_actual_bom |
count(*) WHERE standard_net_quantity = 0 |
fact_recipe_bom |
| 负毛利率菜品 |
ovData.negative_margin_count |
同上 |
negative_margin_count |
count(*) WHERE actual_margin_rate_pct < 0 |
dish_cost_analysis_summary |
| 理论负毛利菜品 |
ovData.negative_theo_margin_count |
同上 |
negative_theo_margin_count |
count(*) WHERE theoretical_margin_rate_pct < 0 |
同上 |
未匹配菜品清单(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 菜品名 |
dishData[].dish_name |
/cost-analysis/unmatched-dishes |
dish_name |
dish_cost_analysis_summary |
| 编码 |
dishData[].dish_code |
同上 |
dish_code |
同上 |
| 品类 |
dishData[].category_level1 |
同上 |
category_level1 |
同上 |
| 销售额 |
dishData[].sales_amount |
同上 |
sales_amount |
同上 |
筛选条件:NOT EXISTS (SELECT 1 FROM dish_sales_details WHERE dish_name = s.dish_name)。
未匹配物料清单(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 物料名 |
matData[].material_name |
/cost-analysis/unmatched-materials |
material_name |
dish_cost_analysis_material_detail |
| 类型 |
matData[].material_type |
同上 |
material_type |
同上 |
| 涉及菜品数 |
matData[].dish_count |
同上 |
dish_count |
count(DISTINCT summary_id) |
| 损耗金额 |
matData[].loss_amount |
同上 |
loss_amount |
sum(loss_amount) |
筛选条件:NOT EXISTS (SELECT 1 FROM inventory_cost_records WHERE material_name = m.material_name)。
Tab8:门店成本(StoreTab)
门店成本总览(6个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店总数 |
ovData.total_stores |
/cost-analysis/store-overview |
total_stores |
count(*) |
mv_store_theoretical_actual_cost_monthly |
| 红色-严重超耗 |
ovData.red_count |
同上 |
red_count |
count(*) FILTER(variance_level='红色-严重超耗') |
同上.variance_level |
| 橙色-明显超耗 |
ovData.orange_count |
同上 |
orange_count |
count(*) FILTER(variance_level='橙色-明显超耗') |
同上 |
| 绿色-基本正常 |
ovData.green_count |
同上 |
green_count |
count(*) FILTER(variance_level='绿色-基本正常') |
同上 |
| 灰色-口径异常 |
ovData.gray_count |
同上 |
gray_count |
count(*) FILTER(variance_level='灰色-口径异常') |
同上 |
| 总超耗金额 |
ovData.total_variance |
同上 |
total_variance |
sum(food_cost_variance) |
同上.food_cost_variance |
门店超耗排名(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rankData[].store_name |
/cost-analysis/store-ranking |
store_name |
— |
mv_store_theoretical_actual_cost_monthly |
| 理论成本率 |
rankData[].theo_cost_rate |
同上 |
theo_cost_rate |
theoretical_cost_rate_pct |
同上 |
| 实际成本率 |
rankData[].actual_cost_rate |
同上 |
actual_cost_rate |
actual_food_cost_rate_pct |
同上 |
| 偏差 |
rankData[].variance_pct |
同上 |
variance_pct |
variance_to_theoretical_pct |
同上 |
| 超耗金额 |
rankData[].variance_amount |
同上 |
variance_amount |
food_cost_variance |
同上 |
| 负库存项 |
rankData[].negative_item_lines |
同上 |
negative_item_lines |
— |
同上.negative_item_lines |
| 分级 |
rankData[].variance_level |
同上 |
variance_level |
— |
同上.variance_level |
Tab9:可视化探索(ExploreTab)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
scatterData[].dish_name |
/cost-analysis/scatter |
dish_name |
— |
dish_cost_analysis_summary |
| 品类 |
scatterData[].category_level1 |
同上 |
category_level1 |
— |
同上 |
| 销量(X轴) |
scatterData[].x |
同上 |
x |
sales_quantity |
同上 |
| 成本差异(Y轴) |
scatterData[].y |
同上 |
y |
cost_variance_amount |
同上 |
| 销售额(气泡大小) |
scatterData[].size |
同上 |
size |
sales_amount |
同上 |
Tab10:调整管理(AdjustmentTab)
子Tab:待处理建议
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品 |
diagData[].dish_name |
/cost-analysis/diagnosis |
dish_name |
— |
dish_diagnosis_snapshot |
| 品类 |
diagData[].category_l1 |
同上 |
category_l1 |
— |
同上 |
| 诊断类型 |
diagData[].diagnosis_type |
同上 |
diagnosis_type |
— |
同上(生成时计算) |
| 诊断详情 |
diagData[].diagnosis_detail |
同上 |
diagnosis_detail |
— |
同上 |
| 理论毛利率 |
diagData[].theoretical_margin_pct |
同上 |
theoretical_margin_pct |
— |
同上 |
| 实际毛利率 |
diagData[].actual_margin_pct |
同上 |
actual_margin_pct |
— |
同上 |
| 成本差异 |
diagData[].cost_variance_amount |
同上 |
cost_variance_amount |
— |
同上 |
| 建议动作 |
diagData[].suggested_action |
同上 |
suggested_action |
— |
同上 |
| 优先级 |
diagData[].priority |
同上 |
priority |
P0/P1/P2/P3 |
同上 |
诊断生成:POST /cost-analysis/diagnosis/generate 从 dish_cost_analysis_summary + BOM数据生成快照写入 dish_diagnosis_snapshot。
子Tab:调整记录
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 菜品 |
adjData[].dish_name |
/cost-analysis/adjustment |
dish_name |
dish_adjustment_log |
| 调整类型 |
adjData[].adjustment_type |
同上 |
adjustment_type |
同上 |
| 执行日期 |
adjData[].effective_date |
同上 |
effective_date |
同上 |
| 调整前毛利率 |
adjData[].before_theoretical_margin |
同上 |
before_theoretical_margin |
同上 |
| 目标毛利率 |
adjData[].after_target_margin |
同上 |
after_target_margin |
同上 |
| 决策人 |
adjData[].decided_by |
同上 |
decided_by |
同上 |
| 状态 |
adjData[].status |
同上 |
status |
同上 |
创建调整:POST /cost-analysis/adjustment → INSERT INTO dish_adjustment_log。
更新状态:PUT /cost-analysis/adjustment/:id → UPDATE status。
子Tab:效果验证
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 调整前日均销量 |
verifyData.before_avg_daily |
/cost-analysis/adjustment/:id/verify |
before_avg_daily |
avg(bills) 前7天 |
dish_sales_details |
| 调整后日均销量 |
verifyData.after_avg_daily |
同上 |
after_avg_daily |
avg(bills) 后7天 |
同上 |
| 销量变化率 |
verifyData.sales_change_pct |
同上 |
sales_change_pct |
(afterAvg - beforeAvg) / beforeAvg * 100 |
— |
| 日销量趋势 |
verifyData.before/after |
同上 |
before/after |
count(*) per day |
dish_sales_details |
七、页面5:门店营业费用 StoreExpensePage
10个Tab,每个Tab独立组件。共调用11个API(全部GET)。
核心数据源:analytics.mv_store_operating_expense_monthly(门店营业费用月度物化视图)+ analytics.mv_store_risk_rating_monthly(门店风险评级月度物化视图)+ analytics.v_operating_expense_account_monthly(费用科目月度视图)。
Tab1:费用总览(ExpenseOverviewTab)
概览指标(6个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
ov.total_consumption |
/store-expense/overview |
total_consumption |
sum(consumption) |
bill_fact.consumption + mv_store_risk_rating_monthly |
| 优惠 |
ov.total_discount |
同上 |
total_discount |
sum(discount) |
同上 |
| 实收合计 |
ov.total_received |
同上 |
total_received |
sum(received) |
mv_store_risk_rating_monthly.received |
| 门店贡献利润 |
ov.total_contribution |
同上 |
total_contribution |
sum(received - actual_food_cost - operating_expense) |
mv_store_operating_expense_monthly |
| 经营门店 |
ov.total_stores |
同上 |
total_stores |
count(*) |
mv_store_risk_rating_monthly |
| 费用率 |
ov.overall_expense_rate_pct |
同上 |
overall_expense_rate_pct |
sum(operating_expense) / sum(received) * 100 |
同上 |
数据关联机制:overview API通过CTE full_scope 关联 mv_store_risk_rating_monthly(主表,按month_start过滤)LEFT JOIN mv_store_operating_expense_monthly(费用明细,按report_month过滤)LEFT JOIN bill_fact(消费/优惠金额)。
费用结构分析(PieChart + 明细表)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 费用科目 |
structureData[].account_name |
/store-expense/expense-structure |
account_name |
— |
v_operating_expense_account_monthly.account_name |
| 金额 |
structureData[].amount |
同上 |
amount |
— |
同上.amount |
| 占比 |
structureData[].expense_share_pct |
同上 |
expense_share_pct |
— |
同上.expense_share_pct |
| 门店数 |
structureData[].nonzero_cost_unit_count |
同上 |
nonzero_cost_unit_count |
— |
同上.nonzero_cost_unit_count |
⚠️ CollapsibleSection subtitle 硬编码日期:subtitle="2026年4月各费用科目占比" 硬编码了月份,应使用 month 变量动态显示。
Tab2:门店费用率排名(StoreRankingTab)
门店费用率排名(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/store-ranking |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上.received |
| 费用合计 |
rows[].operating_expense |
同上 |
operating_expense |
— |
同上.operating_expense |
| 费用率 |
rows[].operating_expense_rate_pct |
同上 |
operating_expense_rate_pct |
— |
同上 |
| 人工率 |
rows[].wage_rate_pct |
同上 |
wage_rate_pct |
— |
同上 |
| 租金率 |
rows[].rent_rate_pct |
同上 |
rent_rate_pct |
— |
同上 |
| 水电率 |
rows[].utility_rate_pct |
同上 |
utility_rate_pct |
— |
同上 |
| 贡献利润 |
rows[].actual_store_contribution |
同上 |
actual_store_contribution |
— |
同上 |
| 贡献率 |
rows[].actual_store_contribution_rate_pct |
同上 |
actual_store_contribution_rate_pct |
— |
同上 |
| 坪效 |
rows[].received_per_sqm |
同上 |
received_per_sqm |
— |
同上 |
筛选条件:filter支持 profitable/loss/zero_sales。排序白名单校验。
Tab3:门店贡献利润(ContributionTab)
门店贡献利润分析(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/store-contribution |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 理论食材成本 |
rows[].theoretical_cost |
同上 |
theoretical_cost |
— |
同上.theoretical_cost |
| 实际食材成本 |
rows[].actual_food_cost |
同上 |
actual_food_cost |
— |
同上.actual_food_cost |
| 营业费用 |
rows[].operating_expense |
同上 |
operating_expense |
— |
同上 |
| 理论贡献 |
rows[].theoretical_store_contribution |
同上 |
theoretical_store_contribution |
— |
同上 |
| 理论贡献率 |
rows[].theoretical_store_contribution_rate_pct |
同上 |
theoretical_store_contribution_rate_pct |
— |
同上 |
| 实际贡献 |
rows[].actual_store_contribution |
同上 |
actual_store_contribution |
received - actual_food_cost - operating_expense |
同上 |
| 实际贡献率 |
rows[].actual_store_contribution_rate_pct |
同上 |
actual_store_contribution_rate_pct |
— |
同上 |
| 贡献差异 |
rows[].contribution_variance |
同上 |
contribution_variance |
actual_store_contribution - theoretical_store_contribution |
同上 |
⚠️ ContributionTab 默认排序方向问题:前端 order 初始值为 'asc'(升序),但后端 /store-contribution 的 order 参数处理为 === 'desc' ? 'DESC' : 'ASC',即非'desc'均为'ASC'。这意味着默认按贡献率升序(最差门店在前),这是合理的行为。但前端 defaultOrder="asc" 与 ContributionTab 的 useState<'asc' | 'desc'>('asc') 一致,无问题。
Tab4:房租及租约风险(RentRiskTab)
房租及租约风险(服务端分页 + riskOnly切换)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/rent-risk |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 租金 |
rows[].rent_expense |
同上 |
rent_expense |
— |
同上 |
| 租金率 |
rows[].rent_rate_pct |
同上 |
rent_rate_pct |
— |
同上 |
| 面积(㎡) |
rows[].area_sqm |
同上 |
area_sqm |
— |
同上 |
| 坪效 |
rows[].received_per_sqm |
同上 |
received_per_sqm |
— |
同上 |
| 租约到期 |
rows[].lease_expiry_date |
同上 |
lease_expiry_date |
— |
同上.lease_expiry_date |
| 风险等级 |
rows[].risk_level |
同上 |
risk_level |
CASE:≤3月=即将到期, ≤12月=年内到期, ≤18月=明年上半年到期, rent>20%=租金占比偏高, else=正常 |
— |
| 建议 |
rows[].suggestion |
同上 |
suggestion |
CASE:按到期/租金率生成建议文本 |
— |
riskOnly 筛选:lease_expiry_date <= month + 12 months OR rent_rate_pct > 20。
⚠️ 租约到期日期显示:前端使用 new Date(r.lease_expiry_date).toLocaleDateString('zh-CN'),后端返回的是日期类型,可能包含时间部分。根据规范应使用 substring(0, 10) 格式化。
Tab5:外卖佣金分析(DeliveryTab)
外卖佣金分析(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/delivery-commission |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 外卖收入 |
rows[].delivery_received |
同上 |
delivery_received |
— |
同上 |
| 外卖占比 |
rows[].delivery_sales_share_pct |
同上 |
delivery_sales_share_pct |
— |
同上 |
| 佣金支出 |
rows[].delivery_commission_expense |
同上 |
delivery_commission_expense |
— |
同上 |
| 佣金率 |
rows[].commission_to_delivery_sales_pct |
同上 |
commission_to_delivery_sales_pct |
— |
同上 |
| 综合平台成本率 |
rows[].combined_platform_cost_rate_pct |
同上 |
combined_platform_cost_rate_pct |
— |
同上 |
| 外卖类型 |
rows[].delivery_type |
同上 |
delivery_type |
CASE:>40%=重度依赖, >25%=外卖占比较高, >10%=正常, else=以堂食为主 |
— |
| 建议 |
rows[].suggestion |
同上 |
suggestion |
CASE:按佣金率/外卖占比/综合成本率生成建议 |
— |
筛选条件:delivery_received > 0。
Tab6:人效坪效(EfficiencyTab)
人效坪效分析(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/efficiency |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 面积(㎡) |
rows[].area_sqm |
同上 |
area_sqm |
— |
同上 |
| 坪效 |
rows[].received_per_sqm |
同上 |
received_per_sqm |
— |
同上 |
| 人工成本 |
rows[].wage_expense |
同上 |
wage_expense |
— |
同上 |
| 人工成本率 |
rows[].wage_rate_pct |
同上 |
wage_rate_pct |
— |
同上 |
| 人效(元/元人工) |
rows[].revenue_per_wage |
同上 |
revenue_per_wage |
received / wage_expense |
同上 |
| 账单数 |
rows[].bill_count |
同上 |
bill_count |
— |
同上 |
| 客单价 |
rows[].avg_ticket_size |
同上 |
avg_ticket_size |
received / bill_count |
同上 |
| 效率等级 |
rows[].efficiency_level |
同上 |
efficiency_level |
CASE:<1000=坪效偏低, <2000=坪效一般, <4000=坪效良好, else=坪效优秀 |
— |
| 建议 |
rows[].suggestion |
同上 |
suggestion |
CASE:按人工率/坪效/面积生成建议 |
— |
筛选条件:received > 0 AND area_sqm IS NOT NULL。
⚠️ 效率等级缺少"坪效极低"档位:后端 efficiency_level CASE 只有4档(偏低/一般/良好/优秀),但前端 EfficiencyTab 的颜色判断有5档(极低<500/偏低<1000/一般/良好/优秀),前端 efficiency_level === '坪效极低' 永远不会匹配。后端 loss-diagnosis 中的 efficiency_status 才有"坪效极低"档(<500)。
Tab7:固定/变动费用(FixedVariableTab)
固定/变动费用拆分(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/fixed-variable |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 固定费用 |
rows[].fixed_expense |
同上 |
fixed_expense |
rent_expense + dorm_expense + repair_clean_expense * 0.5 |
同上 |
| 固定费用率 |
rows[].fixed_rate_pct |
同上 |
fixed_rate_pct |
fixed_expense / received * 100 |
同上 |
| 变动费用 |
rows[].variable_expense |
同上 |
variable_expense |
wage_expense + utility_expense + delivery_commission_expense + card_fee_expense + repair_clean_expense * 0.5 |
同上 |
| 变动费用率 |
rows[].variable_rate_pct |
同上 |
variable_rate_pct |
variable_expense / received * 100 |
同上 |
| 边际贡献(扣变动) |
rows[].contribution_after_variable |
同上 |
contribution_after_variable |
received - actual_food_cost - wage_expense - utility_expense - delivery_commission_expense - card_fee_expense - repair_clean_expense * 0.5 |
同上 |
| 盈亏平衡销售额 |
rows[].break_even_sales |
同上 |
break_even_sales |
fixed_expense(即 rent_expense + dorm_expense + repair_clean_expense * 0.5) |
同上 |
⚠️ 盈亏平衡销售额计算错误:后端 break_even_sales 直接等于 fixed_expense(固定费用),但正确的盈亏平衡公式应为 固定费用 ÷ (1 - 食材成本率) 或 固定费用 ÷ 边际贡献率。当前计算仅返回固定费用金额本身,并非真正的盈亏平衡点。Tab8 break-even 中的计算才是正确的。
Tab8:盈亏平衡分析(BreakEvenTab)
盈亏平衡分析(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/break-even |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 食材成本 |
rows[].actual_food_cost |
同上 |
actual_food_cost |
— |
同上 |
| 食材成本率 |
rows[].food_cost_rate_pct |
同上 |
food_cost_rate_pct |
actual_food_cost / received * 100 |
同上 |
| 营业费用 |
rows[].operating_expense |
同上 |
operating_expense |
— |
同上 |
| 费用率 |
rows[].expense_rate_pct |
同上 |
expense_rate_pct |
operating_expense / received * 100 |
同上 |
| 盈亏平衡销售额 |
rows[].break_even_sales |
同上 |
break_even_sales |
operating_expense / (1 - actual_food_cost/received) |
同上 |
| 销售缺口 |
rows[].sales_gap |
同上 |
sales_gap |
received - break_even_sales |
同上 |
| 安全边际率 |
rows[].safety_margin_pct |
同上 |
safety_margin_pct |
(received - break_even_sales) / break_even_sales * 100 |
同上 |
| 安全状态 |
rows[].safety_status |
同上 |
safety_status |
CASE:贡献边际≤0=无法盈利, received<平衡点=未达盈亏平衡, <15%=接近, <30%=较低, else=充足 |
— |
正确的盈亏平衡公式:break_even_sales = operating_expense / (1 - food_cost_ratio),即 营业费用 ÷ (1 - 食材成本率)。与Tab7的简单固定费用公式不同。
Tab9:亏损门店诊断(LossDiagnosisTab)
概览指标(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 亏损门店数 |
meta.total |
/store-expense/loss-diagnosis |
meta.total |
count(*) WHERE actual_store_contribution <= 0 AND received > 0 |
mv_store_operating_expense_monthly |
| P0 紧急 |
p0Count |
同上 |
前端计算 |
rows.filter(priority === 'P0').length |
— |
| P1 整改 |
p1Count |
同上 |
前端计算 |
rows.filter(priority === 'P1').length |
— |
| 亏损金额合计 |
totalLoss |
同上 |
前端计算 |
rows.reduce(sum + actual_store_contribution) |
— |
⚠️ P0/P1/亏损金额仅统计当前页:p0Count、p1Count、totalLoss 是从当前页 rows 计算的,而非全量数据。当翻页时这些指标会变化,不具备全局统计意义。应在后端返回全量统计或单独查询。
亏损门店诊断明细(服务端分页 + 弹窗详情)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/loss-diagnosis |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 优先级 |
rows[].priority |
同上 |
后端计算 |
CASE:贡献率<-20%=P0, <-5%=P1, <0=P2, else=P3 |
— |
| 亏损类型 |
rows[].loss_type |
同上 |
loss_type |
CASE:理论贡献≤0=理论即亏损, 实际超耗=实际超耗导致亏损, else=费用过高导致亏损 |
— |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 贡献利润 |
rows[].actual_store_contribution |
同上 |
actual_store_contribution |
— |
同上 |
| 贡献率 |
rows[].actual_store_contribution_rate_pct |
同上 |
actual_store_contribution_rate_pct |
— |
同上 |
| 人工率 |
rows[].wage_rate_pct |
同上 |
wage_rate_pct |
— |
同上 |
| 租金率 |
rows[].rent_rate_pct |
同上 |
rent_rate_pct |
— |
同上 |
| 坪效 |
rows[].received_per_sqm |
同上 |
received_per_sqm |
— |
同上 |
| 亏损原因 |
rows[].diagnosis_reasons |
同上 |
后端JS生成 |
按收入/食材/人工/租金/水电/外卖/坪效/租约/亏损类型多维度拼接 |
— |
| 建议动作 |
rows[].suggested_actions |
同上 |
后端JS生成 |
对应改进建议动作列表 |
— |
诊断状态字段(弹窗详情):revenue_status、food_cost_status、wage_status、rent_status、utility_status、delivery_status、efficiency_status、lease_status 均由后端SQL CASE生成。
⚠️ 租约到期日期显示:弹窗中使用 new Date(store.lease_expiry_date).toLocaleDateString('zh-CN'),应使用 substring(0, 10) 规范格式。
Tab10:关停/续租/改造评估(StoreEvaluationTab)
概览指标(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 关停评估 |
evalStats['关停评估'] |
/store-expense/store-evaluation |
meta.evalStats.关停评估 |
后端全量统计 |
mv_store_operating_expense_monthly |
| 改造评估 |
evalStats['改造评估'] |
同上 |
meta.evalStats.改造评估 |
后端全量统计 |
同上 |
| 续租评估 |
evalStats['续租评估'] |
同上 |
meta.evalStats.续租评估 |
后端全量统计 |
同上 |
| 关注观察 |
evalStats['关注观察'] |
同上 |
meta.evalStats.关注观察 |
后端全量统计 |
同上 |
evalStats 全量统计:后端在返回分页数据的同时,额外执行一条全量统计SQL获取各评估类型数量,不受分页影响。与Tab9的仅当前页统计形成对比。
门店评估明细(服务端分页 + 弹窗详情)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].sales_store_name |
/store-expense/store-evaluation |
sales_store_name |
— |
mv_store_operating_expense_monthly |
| 优先级 |
rows[].priority |
同上 |
priority |
CASE:received<5000=P0, 贡献率<-20%=P0, <-10%=P1, <0=P2, <10=P3, else=P4 |
— |
| 评估类型 |
rows[].evaluation_type |
同上 |
evaluation_type |
CASE:received<5000=关停评估, 贡献率<-20%&租约到期=关停评估, 贡献率<-10%&坪效<1000=关停评估, 贡献率<0&租约到期=关停或迁址评估, 贡献率<0&坪效<1000&面积>400=改造评估, 贡献率<0&人工率>35=改造评估, 贡献率<0=关注观察, 租约≤3月=续租评估, 贡献率<10=关注观察, else=正常经营 |
— |
| 实收 |
rows[].received |
同上 |
received |
— |
同上 |
| 贡献利润 |
rows[].actual_store_contribution |
同上 |
actual_store_contribution |
— |
同上 |
| 贡献率 |
rows[].actual_store_contribution_rate_pct |
同上 |
actual_store_contribution_rate_pct |
— |
同上 |
| 坪效 |
rows[].received_per_sqm |
同上 |
received_per_sqm |
— |
同上 |
| 租约到期 |
rows[].lease_expiry_date |
同上 |
lease_expiry_date |
后端格式化为 toISOString().split('T')[0] |
同上 |
| 评估详情 |
rows[].evaluation_detail |
同上 |
后端JS生成 |
按评估类型生成详细说明 |
— |
八、页面6:风险与内控 RiskPage
单页面无子组件文件,4个Tab切换(异常账单/全额优惠/空单/收银员风险),3个API(全部GET)。
核心数据源:mv_risk_anomaly(异常账单物化视图)、mv_risk_zero(零实收账单物化视图)、mv_risk_cashier(收银员风险物化视图)。均按 month = to_char($1::date, 'YYYY-MM') 过滤。
概览指标(5个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 异常账单数 |
totalAnomaly |
/risk/anomaly |
meta.total |
count(*) |
mv_risk_anomaly |
| 全额优惠账单 |
zeroMeta.full_discount |
/risk/zero-received |
meta.full_discount |
count(*) FILTER (zero_received_type='全额优惠') |
mv_risk_zero |
| 空单账单 |
zeroMeta.empty_bill |
同上 |
meta.empty_bill |
count(*) FILTER (zero_received_type='无消费无优惠') |
同上 |
| 高风险收银员(≥10%) |
highRiskCashiers |
/risk/cashier |
前端计算 |
cashierRows.filter(anomaly_rate_pct >= 10).length |
mv_risk_cashier |
| 平均异常率 |
avgAnomalyRate |
同上 |
前端计算 |
sum(anomaly_rate_pct) / cashierRows.length |
同上 |
⚠️ highRiskCashiers 和 avgAnomalyRate 基于全量收银员数据计算:/risk/cashier 不分页,返回全量收银员列表,所以这两个指标是全局准确的。与StoreExpensePage Tab9的当前页统计问题不同。
收银员异常账单数TOP15(BarChart)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 收银员 |
cashierChartData[].cashier |
/risk/cashier |
cashier |
— |
mv_risk_cashier |
| 异常账单数 |
cashierChartData[].anomaly_bills |
同上 |
anomaly_bills |
anomaly_no_received + anomaly_discount_over + anomaly_unbalanced |
同上 |
图表数据:取 cashierRows 按 anomaly_bills 降序排列前15条。
Tab1:异常账单(anomaly)
异常账单明细(服务端分页 + 多维筛选)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
anomalyRows[].store_name |
/risk/anomaly |
store_name |
— |
mv_risk_anomaly |
| 账单号 |
anomalyRows[].bill_no |
同上 |
bill_no |
— |
同上 |
| 餐段 |
anomalyRows[].meal_period |
同上 |
meal_period |
— |
同上 |
| 消费额 |
anomalyRows[].consumption |
同上 |
consumption |
— |
同上 |
| 优惠 |
anomalyRows[].discount_total |
同上 |
discount_total |
— |
同上 |
| 实收 |
anomalyRows[].received_total |
同上 |
received_total |
— |
同上 |
| 异常原因 |
anomalyRows[].anomaly_reason |
同上 |
anomaly_reason |
— |
同上 |
| 收银员 |
anomalyRows[].cashier |
同上 |
cashier |
— |
同上 |
| 结账时间 |
anomalyRows[].closed_at |
同上 |
closed_at |
— |
同上 |
筛选条件:store(门店精确匹配)、reason(异常原因精确匹配)、cashier(ILIKE模糊搜索,前端400ms debounce)。
排序白名单:consumption、discount_total、received_total、closed_at。
筛选合计:后端在count查询中同时返回 sum_consumption、sum_discount、sum_received,前端显示筛选合计行。
结账时间格式化:前端使用 r.closed_at?.substring(0, 16) 截取前16位,符合日期格式化规范。
Tab2:全额优惠(full_discount)
全额优惠账单(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
zeroRows[].store_name |
/risk/zero-received |
store_name |
— |
mv_risk_zero |
| 账单号 |
zeroRows[].bill_no |
同上 |
bill_no |
— |
同上 |
| 餐段 |
zeroRows[].meal_period |
同上 |
meal_period |
— |
同上 |
| 消费额 |
zeroRows[].consumption |
同上 |
consumption |
— |
同上 |
| 优惠 |
zeroRows[].discount_total |
同上 |
discount_total |
— |
同上 |
| 收银员 |
zeroRows[].cashier |
同上 |
cashier |
— |
同上 |
| 结账时间 |
zeroRows[].closed_at |
同上 |
closed_at |
— |
同上 |
API请求参数:type='全额优惠',后端按 zero_received_type = '全额优惠' 过滤。
排序:后端固定 ORDER BY consumption DESC,前端 sortOptions 不生效(未传sort参数到后端)。
Tab3:空单(empty_bill)
空单账单(服务端分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 同Tab2 |
同上 |
/risk/zero-received |
同上 |
同上 |
mv_risk_zero |
API请求参数:type='无消费无优惠',后端按 zero_received_type = '无消费无优惠' 过滤。
⚠️ Tab2和Tab3共用同一API和组件结构:zeroType 切换时触发重新请求,zeroPage 重置为1。
Tab4:收银员风险(cashier)
收银员风险明细(全量不分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 收银员 |
cashierRows[].cashier |
/risk/cashier |
cashier |
— |
mv_risk_cashier |
| 账单数 |
cashierRows[].bill_count |
同上 |
bill_count |
— |
同上 |
| 实收 |
cashierRows[].received |
同上 |
received |
— |
同上 |
| 异常账单数 |
cashierRows[].anomaly_bills |
同上 |
anomaly_bills |
anomaly_no_received + anomaly_discount_over + anomaly_unbalanced |
同上 |
| 异常率 |
cashierRows[].anomaly_rate_pct |
同上 |
anomaly_rate_pct |
(anomaly_bills / bill_count) * 100 |
同上 |
| 异常消费额 |
cashierRows[].anomaly_consumption |
同上 |
consumption_total |
— |
同上 |
⚠️ 前端字段名与后端不匹配:前端列 anomaly_consumption 对应后端返回的 consumption_total,前端 render: (r) => formatCurrency(r.anomaly_consumption) 访问的 r.anomaly_consumption 在后端返回中不存在(后端返回 consumption_total),导致该列始终显示 ¥0.00。
双击行跳转:onRowDoubleClick 设置 anomalyCashier 并切换到 anomaly Tab,用收银员名筛选异常账单。
排序:前端 sortOptions 有5个选项,但后端固定 ORDER BY anomaly_bills DESC,前端排序不生效(未传sort参数到后端)。
九、页面7:成本与库存 CostPage
单页面无子组件文件,4个区块(成本概览+散点图+成本对比表+库存效率+原料分类基准),3个API(全部GET)。
核心数据源:analytics.mv_store_theoretical_actual_cost_monthly(理论vs实际成本月度物化视图)、analytics.mv_inventory_cost_classified_monthly(库存分类成本月度物化视图)、analytics.mv_store_area_efficiency_monthly(门店面积效率月度物化视图)。均按 month_start = $1 过滤。
区块1:成本概览(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 平均理论成本率 |
avgTheoreticalRate |
/cost/comparison |
前端计算 |
avg(theoretical_cost_rate_pct) 排除口径异常 |
mv_store_theoretical_actual_cost_monthly |
| 平均实际成本率 |
avgActualRate |
同上 |
前端计算 |
avg(actual_food_cost_rate_pct) 排除口径异常 |
同上 |
| 高偏差门店(>20%) |
highVarianceCount |
同上 |
前端计算 |
filter(variance_to_theoretical_pct > 20).length 排除口径异常 |
同上 |
| 口径异常门店 |
abnormalRows.length |
同上 |
前端计算 |
filter(variance_level includes '口径异常').length |
同上 |
口径异常处理:前端将 variance_level 包含"口径异常"的门店分离为 abnormalRows,不纳入平均成本率和高偏差统计。显示异常门店名称列表。
全量数据:/cost/comparison 不分页,返回全量门店数据,前端统计是全局准确的。
区块2:理论vs实际成本率散点图(ScatterChart)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店名 |
scatterData[].name |
/cost/comparison |
store_name |
— |
mv_store_theoretical_actual_cost_monthly |
| 理论成本率 |
scatterData[].theoretical |
同上 |
theoretical_cost_rate_pct |
— |
同上 |
| 实际成本率 |
scatterData[].actual |
同上 |
actual_food_cost_rate_pct |
— |
同上 |
| 偏差 |
scatterData[].variance |
同上 |
variance_to_theoretical_pct |
— |
同上 |
散点图排除口径异常门店。X轴=理论成本率,Y轴=实际成本率,对角线参考线表示理论=实际。偏离对角线越多偏差越大。
动态坐标轴:useMemo 计算数据范围 ±1 作为domain,空数据时默认 [0,40]×[0,50]。
区块3:门店成本对比表(FilterableTable,全量不分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
costRows[].store_name |
/cost/comparison |
store_name |
— |
mv_store_theoretical_actual_cost_monthly |
| 理论成本率 |
costRows[].theoretical_cost_rate_pct |
同上 |
theoretical_cost_rate_pct |
— |
同上 |
| 实际成本率 |
costRows[].actual_food_cost_rate_pct |
同上 |
actual_food_cost_rate_pct |
— |
同上 |
| 偏差 |
costRows[].variance_to_theoretical_pct |
同上 |
variance_to_theoretical_pct |
— |
同上 |
| 偏差等级 |
costRows[].variance_level |
同上 |
variance_level |
— |
同上 |
| 实际食材成本 |
costRows[].actual_food_cost |
同上 |
actual_food_cost |
— |
同上 |
筛选:filterKey="variance_level" 按偏差等级筛选。排序:前端 sortOptions 有5个选项,但后端固定 ORDER BY variance_to_theoretical_pct DESC,前端排序为客户端排序(全量数据)。
⚠️ 前端排序 vs 后端排序:/cost/comparison 不分页返回全量数据,FilterableTable 未设 serverSide,排序在前端完成,是有效的。
区块4:库存效率(FilterableTable,懒加载)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
invRows[].store_name |
/cost/inventory |
store_name |
— |
mv_store_area_efficiency_monthly + mv_store_theoretical_actual_cost_monthly |
| 业态 |
invRows[].business_type |
同上 |
business_type |
— |
mv_store_area_efficiency_monthly |
| 规模 |
invRows[].scale_tier |
同上 |
scale_tier |
— |
同上 |
| 库存天数 |
invRows[].estimated_inventory_days |
同上 |
estimated_inventory_days |
— |
同上 |
| 期末库存 |
invRows[].ending_inventory_amount |
同上 |
ending_inventory_amount |
— |
mv_store_theoretical_actual_cost_monthly |
| 负耗用行数 |
invRows[].negative_item_lines |
同上 |
negative_item_lines |
— |
同上 |
懒加载:enabled: invOpen,仅在CollapsibleSection展开时请求。onToggle={setInvOpen} 控制展开状态。
数据关联:mv_store_area_efficiency_monthly LEFT JOIN mv_store_theoretical_actual_cost_monthly ON store_code + month_start。
区块5:原料分类成本基准(FilterableTable,懒加载)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
catRows[].store_name |
/cost/category-benchmark |
store_name |
— |
mv_inventory_cost_classified_monthly |
| 财务分类 |
catRows[].finance_category |
同上 |
finance_category |
— |
同上 |
| 实际成本 |
catRows[].actual_category_cost |
同上 |
actual_category_cost |
sum(consumption_amount) GROUP BY store_name, finance_category |
同上 |
| 每万元成本 |
catRows[].cost_per_10k_sales |
同上 |
cost_per_10k_sales |
actual_category_cost / sales_received * 10000 |
同上 + mv_store_theoretical_actual_cost_monthly |
| 同业中位 |
catRows[].peer_median_cost_per_10k |
同上 |
peer_median_cost_per_10k |
percentile_cont(0.5) WITHIN GROUP (ORDER BY cost_per_10k_sales) 按分类 |
— |
| 超出同业 |
catRows[].excess_vs_peer_per_10k |
同上 |
excess_vs_peer_per_10k |
cost_per_10k_sales - peer_median |
— |
懒加载:enabled: catOpen。同业基准:使用 percentile_cont(0.5) 计算各财务分类的每万元成本中位数作为同业基准。
十、页面8:会员与复购 MemberPage
单页面无子组件文件,4个区块(会员概览+对比图+对比明细+复购率),2个API(全部GET)。
核心数据源:analytics.bill_fact(账单事实表,按closed_at月份过滤)、analytics.v_store_repeat_summary_monthly(门店复购汇总月度视图,按month_start过滤)。
区块1:会员概览(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 会员账单占比 |
memberBillShare |
/member/comparison |
前端计算 |
memberRow.bill_count / (memberRow.bill_count + nonMemberRow.bill_count) * 100 |
bill_fact |
| 会员收入占比 |
memberRevenueShare |
同上 |
前端计算 |
memberRow.received / (memberRow.received + nonMemberRow.received) * 100 |
同上 |
| 平均复购率 |
avgRepeatRate |
/member/repeat |
前端计算 |
avg(repeat_rate_pct) |
v_store_repeat_summary_monthly |
| 低复购门店(<30%) |
lowRepeatCount |
同上 |
前端计算 |
filter(repeat_rate_pct < 30).length |
同上 |
全量数据:两个API均不分页,返回全量数据,前端统计全局准确。
区块2:会员vs非会员消费对比(BarChart + PieChart)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 客户类型 |
cmpChartData[].name |
/member/comparison |
customer_type |
CASE WHEN member_id IS NULL THEN '非会员' ELSE '会员' |
bill_fact |
| 账单数 |
cmpChartData[].账单数 |
同上 |
bill_count |
count(*) |
同上 |
| 实收 |
cmpChartData[].实收 |
同上 |
received |
sum(received_total) |
同上 |
| 客单价 |
cmpChartData[].客单价 |
同上 |
avg_bill_value |
avg(received_total) |
同上 |
BarChart双Y轴:左轴=账单数+实收,右轴=客单价。PieChart显示会员/非会员账单数占比。
区块3:会员与非会员指标对比(FilterableTable,全量不分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 客户类型 |
cmpRows[].customer_type |
/member/comparison |
customer_type |
— |
bill_fact |
| 账单数 |
cmpRows[].bill_count |
同上 |
bill_count |
count(*) |
同上 |
| 实收 |
cmpRows[].received |
同上 |
received |
sum(received_total) |
同上 |
| 客单价 |
cmpRows[].avg_bill_value |
同上 |
avg_bill_value |
avg(received_total) |
同上 |
| 优惠率 |
cmpRows[].discount_rate_pct |
同上 |
discount_rate_pct |
sum(discount_total) / sum(consumption) * 100 |
同上 |
| 理论毛利率 |
cmpRows[].theoretical_margin_pct |
同上 |
theoretical_margin_pct |
sum(theoretical_profit) / sum(received_total) * 100 |
同上 |
仅2行数据(会员/非会员),客户端排序有效。
区块4:门店复购率(FilterableTable,全量不分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 门店 |
repeatRows[].store_name |
/member/repeat |
store_name |
— |
v_store_repeat_summary_monthly |
| 识别会员数 |
repeatRows[].identified_members |
同上 |
identified_members |
— |
同上 |
| 复购会员数 |
repeatRows[].repeat_members |
同上 |
repeat_members |
— |
同上 |
| 复购率 |
repeatRows[].repeat_rate_pct |
同上 |
repeat_rate_pct |
— |
同上 |
| 人均消费次数 |
repeatRows[].avg_orders |
同上 |
avg_orders |
— |
同上 |
| 复购收入占比 |
repeatRows[].repeat_revenue_share_pct |
同上 |
repeat_revenue_share_pct |
— |
同上 |
筛选:filterKey="store_name" 按门店筛选。排序:前端 sortOptions 客户端排序(全量数据,有效)。后端固定 ORDER BY repeat_rate_pct DESC。
复购率颜色:≥50%绿色,≥30%黄色,<30%红色。
发现的问题汇总
MemberPage 无发现新问题。页面结构简洁,API与前端字段匹配,全量数据统计准确,日期无特殊格式化需求。
十一、页面9:商品SKU管理 SKUPage
单页面无子组件文件,5个区块(SKU概览+ABC分布图+品类分布+SKU明细+长尾治理),2个API(全部GET)。
核心数据源:analytics.mv_dish_sku_abc_monthly(菜品SKU ABC分析月度物化视图,按month_start过滤)、analytics.category_summary(品类汇总表,无月份过滤)。
区块1:SKU概览(4个MetricCard)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 总SKU数 |
totalSku |
/sku/abc |
前端计算 |
data.length |
mv_dish_sku_abc_monthly |
| A类SKU(核心) |
abcSummary['A-核心']?.sku_count |
同上 |
前端计算 |
reduce(abc_class='A-核心').count |
同上 |
| C类SKU(长尾) |
cClassCount |
同上 |
前端计算 |
abcSummary['C-长尾']?.sku_count |
同上 |
| 低价值SKU(<¥1000) |
lowValueSku |
同上 |
前端计算 |
filter(received_amount < 1000).length |
同上 |
全量数据:/sku/abc 不分页,返回全量SKU列表,前端统计全局准确。
区块2:SKU ABC分布(PieChart)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| ABC分类 |
abcPieData[].name |
/sku/abc |
abc_class |
— |
mv_dish_sku_abc_monthly |
| SKU数量 |
abcPieData[].value |
同上 |
前端计算 |
reduce(sku_count++) |
同上 |
| 实收 |
abcPieData[].received |
同上 |
前端计算 |
reduce(received_amount +=) |
同上 |
PieChart按ABC分类显示SKU数量分布,Tooltip同时显示SKU数和实收金额。
区块3:品类实收分布(BarChart)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 品类名 |
catRows[].category_name |
/sku/category |
category_name |
— |
category_summary |
| 实收 |
catRows[].amount |
同上 |
amount |
— |
同上 |
BarChart取 catRows.slice(0, 10) 前10个品类。水平柱状图,Y轴=品类名,X轴=金额。
⚠️ /sku/category 无月份过滤:后端查询 SELECT * FROM analytics.category_summary ORDER BY amount DESC,不接受month参数,返回全量品类汇总。前端也未传month参数。如果品类数据需要按月过滤,此处存在口径不一致。
区块4:SKU明细(FilterableTable,全量不分页)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品名称 |
skuRows[].dish_name |
/sku/abc |
dish_name |
— |
mv_dish_sku_abc_monthly |
| 一级品类 |
skuRows[].category_level1 |
同上 |
category_level1 |
— |
同上 |
| ABC分类 |
skuRows[].abc_class |
同上 |
abc_class |
— |
同上 |
| 象限 |
skuRows[].sales_quadrant |
同上 |
sales_quadrant |
— |
同上 |
| 覆盖门店 |
skuRows[].store_count |
同上 |
store_count |
— |
同上 |
| 账单数 |
skuRows[].bill_count |
同上 |
bill_count |
— |
同上 |
| 实收 |
skuRows[].received_amount |
同上 |
received_amount |
— |
同上 |
| 占比 |
skuRows[].revenue_share_pct |
同上 |
revenue_share_pct |
— |
同上 |
| 优惠率 |
skuRows[].discount_rate_pct |
同上 |
discount_rate_pct |
— |
同上 |
筛选:filterKey="abc_class" 按ABC分类筛选。排序:前端客户端排序(全量数据,有效)。后端固定 ORDER BY cumulative_revenue_share。
区块5:长尾治理建议(3个可展开区块)
5a. 低价值SKU(received_amount < 1000)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 菜品名称 |
lowValueSkuRows[].dish_name |
/sku/abc |
dish_name |
— |
mv_dish_sku_abc_monthly |
| 一级品类 |
lowValueSkuRows[].category_level1 |
同上 |
category_level1 |
— |
同上 |
| ABC分类 |
lowValueSkuRows[].abc_class |
同上 |
abc_class |
— |
同上 |
| 覆盖门店 |
lowValueSkuRows[].store_count |
同上 |
store_count |
— |
同上 |
| 账单数 |
lowValueSkuRows[].bill_count |
同上 |
bill_count |
— |
同上 |
| 实收 |
lowValueSkuRows[].received_amount |
同上 |
received_amount |
— |
同上 |
前端筛选:received_amount < 1000,按 received_amount 升序排列。filterKey="category_level1" 按品类筛选。
5b. 单店专属SKU(store_count <= 1)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 同5a |
singleStoreSkuRows[] |
/sku/abc |
同上 |
filter(store_count <= 1) |
同上 |
5c. 合并/归档候选(套餐/赠品/餐具类)
| 显示指标 |
前端变量 |
API |
API字段 |
计算公式 |
数据源表 |
| 同5a |
mergeCandidateRows[] |
/sku/abc |
同上 |
filter(dish_name includes 套餐/赠/餐具/打包/纸巾/调料包) |
同上 |
前端按菜品名称关键词筛选合并候选,按 received_amount 升序排列。
十二、页面10:企业协同管理 EnterprisePage
单页面10个Tab,13个API(12个GET + 2个mutation),无MonthPicker。
核心数据源:analytics.v3_* 系列业务管理表(供应商、采购订单、审批流、消息、HR、培训、营销、财务、闭环、审计)。
Tab1:供应链SRM(supplier)
| API |
数据源表 |
说明 |
| /enterprise/suppliers |
analytics.v3_supplier_master |
供应商主数据,按overall_score降序 |
| /enterprise/purchase-orders |
analytics.v3_purchase_order |
采购订单,按created_at降序,LIMIT 100 |
MetricCard:供应商总数、战略供应商、采购订单数、淘汰供应商。
PieChart:供应商分级分布(战略/优选/合格/淘汰)。
日期格式化:r.order_date?.substring(0, 10) ✅
Tab2:供应商对标(benchmark)
| API |
数据源表 |
说明 |
| /enterprise/supplier-benchmark |
v3_purchase_order_item + v3_purchase_order + v3_supplier_master |
跨供应商同SKU价格对比,CTE查询 |
MetricCard:对标SKU数、价格差异大(>20%)、有优化空间(10-20%)、潜在节约。
后端返回 { summary, benchmarks } 结构,前端正确解构。
Tab3:审批流(approval)
| API |
数据源表 |
说明 |
| /enterprise/approvals |
analytics.v3_approval_request |
审批请求列表,LIMIT 100 |
| POST /enterprise/approvals/:id/approve |
同上 + v3_approval_step |
审批操作mutation |
MetricCard:审批总数、待审批、已审批。
日期格式化:(r.created_at || '').substring(0, 19).replace('T', ' ') ✅
Tab4:消息中心(notification)
| API |
数据源表 |
说明 |
| /enterprise/notifications |
analytics.v3_notification |
按user_id或user_role过滤,LIMIT 50 |
| PATCH /enterprise/notifications/:id/read |
同上 |
标记已读mutation |
MetricCard:消息总数、未读、已读。
Tab5:HR人才(hr)
| API |
数据源表 |
说明 |
| /enterprise/hr/talent-matrix |
analytics.dim_employee + analytics.store_task |
人才九宫格(绩效×潜力),LIMIT 200 |
MetricCard:人才总数、明星员工、核心员工、潜力员工。
⚠️ potential_score 硬编码为60:后端 COALESCE(60, 60) AS potential_score,这意味着所有员工的潜力分都是60,九宫格的"潜力"维度实际上没有区分度。只有performance_score有变化(基于store_task完成情况)。
Tab6:培训LMS(lms)
| API |
数据源表 |
说明 |
| /enterprise/training/courses |
analytics.v3_training_course |
课程列表 |
| /enterprise/training/records |
analytics.v3_learning_record |
学习记录,LIMIT 100 |
MetricCard:课程总数、学习记录数、已完成、未完成。
日期格式化:(r.created_at || '').substring(0, 10) ✅
Tab7:营销MA(marketing)
| API |
数据源表 |
说明 |
| /enterprise/campaigns |
analytics.v3_marketing_campaign |
营销活动列表,LIMIT 100 |
| /enterprise/coupons |
analytics.v3_coupon |
券码列表,LIMIT 100 |
MetricCard:活动总数、进行中、券码总数、已核销。
日期格式化:(r.start_date || '').substring(0, 10) ✅
Tab8:财务ERP(finance)
| API |
数据源表 |
说明 |
| /enterprise/budgets |
analytics.v3_budget |
按年度过滤,默认当前年 |
MetricCard:预算总数、总预算、总实际。
日期格式化:r.month?.substring(0, 10) ✅
Tab9:闭环验证(loop)
| API |
数据源表 |
说明 |
| /enterprise/loop-verification |
analytics.v3_loop_verification |
闭环验证列表,LIMIT 100 |
MetricCard:验证总数、已完成、需升级。
日期格式化:(r.check_date || '').substring(0, 10) ✅
Tab10:审计日志(audit)
| API |
数据源表 |
说明 |
| /enterprise/audit-logs |
analytics.v3_audit_log |
审计日志,LIMIT 100 |
日期格式化:(r.created_at || '').substring(0, 19).replace('T', ' ') ✅
十三、页面11:态势感知 SituationalAwarenessPage
单页面4个Tab(健康度/预警/关联/趋势),4个API(全部GET),有MonthPicker。
核心数据源:analytics.mv_store_risk_rating_monthly、analytics.mv_store_theoretical_actual_cost_monthly、analytics.mv_store_repeat_summary_monthly、analytics.store_task、analytics.mv_daily_revenue、public.dish_cost_analysis_summary、salary_detail_records、analytics.mv_store_platform_economics_monthly、bill_records、mv_bill_hourly、mv_store_hourly_staffing、public.store_name_mapping。
Tab1:健康度评分(health)
API: /situational-awareness/health-score
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 门店 |
rows[].store_name |
store_name |
— |
mv_store_risk_rating_monthly |
| 健康分 |
rows[].health_score |
health_score |
8维加权求和(满分100) |
多表CTE |
| 状态 |
rows[].health_status |
health_status |
≥75健康, ≥55亚健康, <55需干预 |
— |
| 风险 |
rows[].risk_level |
risk_level |
— |
mv_store_risk_rating_monthly |
| 实收 |
rows[].received |
received |
— |
同上 |
| 客单价 |
rows[].avg_bill_value |
avg_bill_value |
— |
同上 |
| 毛利率 |
rows[].avg_margin |
avg_margin |
COALESCE(theoretical_margin_pct, 0) |
同上 |
| 成本差异率 |
rows[].avg_cost_variance_pct |
avg_cost_variance_pct |
avg(LEAST(variance_to_theoretical_pct, 50)) |
mv_store_theoretical_actual_cost_monthly |
| 复购率 |
rows[].repeat_rate_pct |
repeat_rate_pct |
max(repeat_rate_pct) |
mv_store_repeat_summary_monthly |
| 任务完成率 |
rows[].task_completion_rate |
task_completion_rate |
count(status IN ('已验收','已回滚')) / count(*) * 100 |
store_task |
8维评分体系:营收规模(20)、成本控制(20)、毛利率(15)、风险等级(10)、复购率(10)、会员占比(10)、任务完成(10)、客单价(5) = 100分。
数据权限:支持 getDataScope 按角色过滤门店。
弹窗详情:点击行展示RadarChart雷达图 + 各维度进度条 + 原始指标 + 跳转门店详情按钮。
全量数据:不分页,客户端排序和筛选。
Tab2:预警中心(alerts)
API: /situational-awareness/alerts
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 总预警 |
d.total |
total |
alerts.length |
多源 |
| 红色预警 |
d.red |
red |
filter(level='red').length |
多源 |
| 橙色预警 |
d.orange |
orange |
filter(level='orange').length |
多源 |
| 预警列表 |
alerts[] |
alerts |
5类预警合并 |
多源 |
5类预警(Promise.all并行查询):
- 营收异动(revenue, red):日营收 < 月均70%,
mv_daily_revenue,LIMIT 10
- 成本异动(cost, red):成本差异率>30%,
dish_cost_analysis_summary,LIMIT 10
- 人力异动(hr, red/orange):考勤异常>3人,
salary_detail_records,LIMIT 10
- 平台依赖(platform, orange):外卖占比>40%,
mv_store_platform_economics_monthly,LIMIT 10
- 任务逾期(task, red/orange):逾期任务,
store_task,LIMIT 10
前端分页:客户端分页 PAGE_SIZE=20,使用 SearchSelect 做门店/类型/等级三维筛选。
⚠️ 预警查询部分不使用month参数:revenue和cost预警查询不传month参数,使用全局最新数据。
Tab3:关联分析(correlation)
API: /situational-awareness/correlation
返回4组关联分析数据:
| 数据组 |
前端变量 |
API字段 |
数据源表 |
说明 |
| 成本-风险 |
costRiskRows |
cost_risk |
mv_store_risk_rating_monthly + mv_store_theoretical_actual_cost_monthly |
成本差异率×风险等级关联状态 |
| 渠道-会员 |
channelRiskRows |
channel_risk |
mv_store_risk_rating_monthly + mv_store_platform_economics_monthly + mv_store_repeat_summary_monthly |
平台占比×会员占比三角分析 |
| 考勤-营收 |
hrRevenueRows |
hr_revenue |
salary_detail_records + v_store_scorecard + store_name_mapping |
出勤率×营收人效关联 |
| 客流-人力 |
staffingRows |
staffing_efficiency |
mv_bill_hourly + mv_store_hourly_staffing |
每小时账单×在岗人数匹配度 |
散点图:成本-风险关联,X=日均实收,Y=超耗率,颜色=风险等级。
4个FilterableTable:每个都有 filterKey + sortOptions + statusFilterKey + statusOptions,客户端排序。
⚠️ 客流-人力匹配查询有容错处理:mv_store_hourly_staffing 可能不存在,try-catch返回空数组。
⚠️ 考勤-营收关联不使用month参数:salary_detail_records 查询无month过滤,使用全量数据。v_store_scorecard 也无month过滤。
Tab4:趋势预测(forecast)
API: /situational-awareness/forecast
| 数据组 |
前端变量 |
API字段 |
数据源表 |
说明 |
| 客流预测 |
trafficRows |
traffic_forecast |
bill_records |
按工作日/周末×小时P85分位预测 |
| 成本趋势 |
costTrendRows |
cost_trend |
dish_cost_analysis_summary |
成本差异恶化TOP20 |
| 人员流失 |
turnoverRows |
turnover_alert |
salary_detail_records |
有离职的门店流失率排名 |
客流预测:从 bill_records 按小时×日类型聚合,计算 avg/P50/P85/波动率,稳定性分级。
LineChart:工作日和周末分别画两条LineChart(avg_bills + p85_bills + p50_bills)。
⚠️ 成本趋势查询不使用month参数:dish_cost_analysis_summary 查询无month/import_id过滤,使用全量最新数据。LIMIT 20。
人员流失:按month参数过滤 leave_date 和 hire_date。
十四、页面12:门店详情 StoreDetailPage
单页面7个Tab(概览/餐段/品类/成本/会员/异常/任务),8个API(全部GET),有MonthPicker。
通过URL参数 :code 获取门店编码,复用 /situational-awareness/health-score API 获取健康度数据。
核心数据源:bill_records、analytics.mv_store_risk_rating_monthly、analytics.mv_store_platform_economics_monthly、analytics.mv_store_benchmark_composite_monthly、analytics.mv_store_action_priority_deep_monthly、analytics.bill_fact、analytics.mv_store_category_mix_monthly、analytics.mv_store_theoretical_actual_cost_monthly、analytics.mv_inventory_cost_classified_monthly、analytics.mv_store_member_opportunity_monthly、analytics.mv_store_repeat_summary_monthly、analytics.v_store_member_monthly_activity、mv_risk_anomaly、analytics.dim_store。
API总览
| API |
Tab |
数据源表 |
说明 |
| /stores/:code |
全局 |
bill_records + mv_store_risk_rating_monthly + mv_store_platform_economics_monthly + mv_store_benchmark_composite_monthly + mv_store_action_priority_deep_monthly |
门店scorecard+风险+平台+基准+行动优先级 |
| /situational-awareness/health-score |
概览 |
同SituationalAwarenessPage Tab1 |
复用健康度API,前端filter by store_code |
| /stores/:code/daily |
概览 |
bill_records |
日度实收趋势 |
| /stores/:code/meal-period |
餐段 |
analytics.bill_fact |
餐段分析+全网对标 |
| /stores/:code/category-mix |
品类 |
analytics.mv_store_category_mix_monthly |
门店vs公司品类结构 |
| /stores/:code/cost |
成本 |
mv_store_theoretical_actual_cost_monthly + mv_inventory_cost_classified_monthly |
成本概览+原料分类对标 |
| /stores/:code/member |
会员 |
mv_store_member_opportunity_monthly + mv_store_repeat_summary_monthly + v_store_member_monthly_activity |
会员占比+复购+月度活跃 |
| /stores/:code/anomalies |
异常 |
mv_risk_anomaly |
异常账单分页查询 |
| /tasks |
任务 |
analytics.store_task |
门店任务列表 |
Tab1:概览(overview)
| 显示指标 |
前端变量 |
API |
API字段 |
数据源表 |
| 门店名 |
sc.store_name |
/stores/:code |
scorecard.store_name |
bill_records |
| 健康分 |
health.health_score |
/situational-awareness/health-score |
health_score |
多表CTE |
| 风险等级 |
risk.risk_level |
/stores/:code |
risk.risk_level |
mv_store_risk_rating_monthly |
| 经营象限 |
quadrant |
同上 |
前端计算 |
日均营收≥18642 & 毛利率≥70% |
| 实收 |
sc.received |
同上 |
scorecard.received |
bill_records |
| 账单数 |
sc.bill_count |
同上 |
scorecard.bill_count |
同上 |
| 客单价 |
sc.avg_bill_value |
同上 |
scorecard.avg_bill_value |
同上 |
| 优惠率 |
sc.discount_rate_pct |
同上 |
scorecard.discount_rate_pct |
同上 |
| 理论毛利率 |
sc.theoretical_margin_pct |
同上 |
scorecard.theoretical_margin_pct |
同上 |
| 会员占比 |
sc.member_bill_share_pct |
同上 |
scorecard.member_bill_share_pct |
同上 |
| 日均实收 |
risk.avg_daily_received |
同上 |
risk.avg_daily_received |
mv_store_risk_rating_monthly |
| 平台实收 |
sd.platform.* |
同上 |
platform.* |
mv_store_platform_economics_monthly |
健康度雷达图:复用SituationalAwarenessPage的8维评分体系,RadarChart + 进度条。
日度趋势:LineChart显示日实收和客单价。X轴 business_date.substring(5, 10) ✅。
偏差指标:前端硬编码公司均值 { daily_rev: 20144, bill: 36.8, ... },与后端计算的中位数(18642)不一致。
Tab2:餐段分析(meal)
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 餐段 |
mealRows[].meal_period |
meal_period |
— |
bill_fact |
| 账单数 |
mealRows[].bill_count |
bill_count |
— |
同上 |
| 实收 |
mealRows[].received |
received |
sum(received_total) |
同上 |
| 平均单价 |
mealRows[].avg_bill |
avg_bill |
sum(received_total)/count(*) |
同上 |
| 全网均价 |
mealRows[].network_avg_bill |
network_avg_bill |
全网同餐段均值 |
同上 |
| vs全网 |
mealRows[].vs_network_pct |
vs_network_pct |
(avg_bill/network_avg_bill - 1) * 100 |
— |
BarChart + FilterableTable,客户端排序。
Tab3:品类结构(category)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 门店品类 |
cat.store.* |
store.* |
mv_store_category_mix_monthly |
|
| 公司品类 |
cat.company.* |
company.* |
同上(全量汇总) |
|
PieChart(门店品类占比) + BarChart(门店vs公司占比对比) + 4个MetricCard。
品类包括:兰州拉面、西式简餐、外卖套餐、冷菜、丝路美食。
Tab4:成本分析(cost)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 理论成本率 |
cost.cost.theoretical_cost_rate_pct |
theoretical_cost_rate_pct |
mv_store_theoretical_actual_cost_monthly |
|
| 实际成本率 |
cost.cost.actual_food_cost_rate_pct |
actual_food_cost_rate_pct |
同上 |
|
| 差异率 |
cost.cost.variance_to_theoretical_pct |
variance_to_theoretical_pct |
同上 |
|
| 差异等级 |
cost.cost.variance_level |
variance_level |
同上 |
|
| 原料分类 |
cost.categories[] |
categories |
mv_inventory_cost_classified_monthly |
|
FilterableTable展示原料分类成本对标,含消耗金额、实际占比、公司基准、差异。
Tab5:会员分析(member)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 会员占比 |
member.opportunity.member_share_pct |
opportunity.member_share_pct |
mv_store_member_opportunity_monthly |
|
| 公司均值 |
member.opportunity.company_member_share_pct |
opportunity.company_member_share_pct |
同上 |
|
| 复购率 |
member.repeat.repeat_rate_pct |
repeat.repeat_rate_pct |
mv_store_repeat_summary_monthly |
|
| 复购收入占比 |
member.repeat.repeat_revenue_share_pct |
repeat.repeat_revenue_share_pct |
同上 |
|
| 活跃会员数 |
member.monthly.member_count |
monthly.member_count |
v_store_member_monthly_activity |
|
| 人均订单 |
member.monthly.avg_orders |
monthly.avg_orders |
同上 |
|
| 人均消费 |
member.monthly.avg_received |
monthly.avg_received |
同上 |
|
提升机会文案:member.opportunity.conversion_bill_scenario + revenue_uplift_scenario。
Tab6:异常账单(anomaly)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 账单号 |
anomalyRows[].bill_no |
bill_no |
mv_risk_anomaly |
|
| 餐段 |
anomalyRows[].meal_period |
meal_period |
同上 |
|
| 消费额 |
anomalyRows[].consumption |
consumption |
同上 |
|
| 优惠 |
anomalyRows[].discount_total |
discount_total |
同上 |
|
| 实收 |
anomalyRows[].received_total |
received_total |
同上 |
|
| 异常原因 |
anomalyRows[].anomaly_reason |
anomaly_reason |
同上 |
|
| 结账时间 |
anomalyRows[].closed_at |
closed_at |
同上 |
|
后端分页查询,前端 page_size=200 一次性加载。日期格式化:r.closed_at?.substring(0, 16) ✅。
Tab7:任务列表(tasks)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 问题指标 |
tasks[].problem_indicator |
problem_indicator |
store_task |
|
| 优先级 |
tasks[].priority |
priority |
同上 |
|
| 行动要求 |
tasks[].action_required |
action_required |
同上 |
|
| 状态 |
tasks[].status |
status |
同上 |
|
| 截止日 |
tasks[].deadline |
deadline |
同上 |
|
日期格式化:r.deadline?.substring(0, 10) ✅。点击行跳转 /tasks/:task_id。
十五、页面13:门店分级与风险等级 StoreGradePage
单页面2个Tab(门店分级/关停测算),3个API(2 GET + 1 POST mutation),有月份选择器(原生 <input type="month"> 而非 MonthPicker 组件)。
核心数据源:analytics.v3_store_grade、analytics.mv_store_risk_rating、analytics.v3_store_monthly_target、analytics.dim_store、analytics.mv_store_operating_expense_monthly、analytics.mv_store_area_efficiency_monthly。
API总览
| API |
Tab |
方法 |
数据源表 |
说明 |
| /store-grade/grades |
分级 |
GET |
v3_store_grade + mv_store_risk_rating |
分级列表+风险详情 |
| /store-grade/auto-grade |
分级 |
POST |
dim_store + mv_store_risk_rating + v3_store_monthly_target → v3_store_grade |
自动分级计算并写入 |
| /store-grade/closure-analysis |
关停 |
GET |
v3_store_grade + mv_store_risk_rating + mv_store_operating_expense_monthly + mv_store_area_efficiency_monthly |
关停成本测算 |
Tab1:门店分级(grade)
API: /store-grade/grades
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 门店编码 |
r.store_code |
store_code |
— |
v3_store_grade |
| 门店名称 |
r.store_name |
store_name |
— |
同上 |
| 区域 |
r.region |
region |
— |
同上 |
| 分级 |
r.grade |
grade |
A≥85, B≥70, C≥50, D<50 |
auto-grade计算 |
| 综合分 |
r.overall_score |
overall_score |
达成率×0.4+毛利率×0.25+会员占比×0.15+风险×0.2 |
auto-grade计算 |
| 营收达成率 |
r.revenue_achievement_pct |
revenue_achievement_pct |
revenue / revenue_target × 100 |
auto-grade计算 |
| 风险等级 |
r.risk_level |
risk_level |
— |
mv_store_risk_rating |
| 分级原因 |
r.reason |
reason |
— |
auto-grade写入 |
| 营收 |
r.revenue |
revenue |
— |
mv_store_risk_rating |
| 毛利率 |
r.margin_pct |
margin_pct |
— |
同上 |
| 优惠率 |
r.discount_rate |
discount_rate |
— |
同上 |
| 异常率 |
r.anomaly_rate |
anomaly_rate |
— |
同上 |
| 会员占比 |
r.member_pct |
member_pct |
— |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
— |
同上 |
| 活跃天数 |
r.active_days |
active_days |
— |
同上 |
自动分级公式:overallScore = achievementScore×0.4 + marginScore×0.25 + memberScore×0.15 + riskScore×0.2
- achievementScore = min(achievement, 100)
- marginScore = min(margin_pct/50×100, 100)
- memberScore = min(member_pct/50×100, 100)
- riskScore = 红色30, 黄色60, 绿色100
弹窗详情:RadarChart 4维(达成率/综合分/毛利率/异常率) + 13项指标列表。
PieChart:分级分布 + 风险等级分布。
FilterableTable:filterKey=grade, sortOptions=综合分/达成率/门店。
API: /store-grade/auto-grade (POST mutation)
前端点击"自动分级"按钮触发 POST,后端读取 dim_store + mv_store_risk_rating + v3_store_monthly_target,计算综合分和分级,写入 v3_store_grade 表(UPSERT)。成功后前端 invalidateQueries 刷新列表。
Tab2:关停测算(closure)
API: /store-grade/closure-analysis
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 月收入 |
r.monthly_revenue |
monthly_revenue |
— |
mv_store_risk_rating |
| 月利润 |
r.monthly_profit |
monthly_profit |
actual_store_contribution |
mv_store_operating_expense_monthly |
| 月租 |
r.monthly_rent |
monthly_rent |
rent_expense |
同上 |
| 月人工 |
r.monthly_wage |
monthly_wage |
wage_expense |
同上 |
| 关停成本 |
r.total_closure_cost |
total_closure_cost |
wage×1.5 + rent×2 + revenue×0.05 |
— |
| 遣散费 |
— |
severance_cost |
monthly_wage × 1.5 |
— |
| 违约金 |
— |
lease_termination_cost |
monthly_rent × 2 |
— |
| 资产处置 |
— |
asset_disposal_cost |
monthly_revenue × 0.05 |
— |
| 12月亏损 |
r.projected_12m_loss |
projected_12m_loss |
monthly_profit < 0 ? monthly_profit × 12 : 0 |
— |
| 月节省 |
r.monthly_savings_if_closed |
monthly_savings_if_closed |
monthly_profit < 0 ? abs(monthly_profit) : 0 |
— |
| 回本月数 |
r.payback_months |
payback_months |
total_closure_cost / abs(monthly_profit) |
— |
| 建议 |
r.recommendation |
recommendation |
亏损+D级→关停, 亏损+C级→整改, 微利+低分→重点整改, else→持续经营 |
— |
| 原因 |
r.reason |
reason |
— |
— |
汇总指标:total_stores, recommend_close, recommend_rectify, total_closure_cost, total_projected_loss, total_monthly_savings。
PieChart:关停建议分布(建议关停/整改观察/持续经营)。
FilterableTable:filterKey=recommendation, sortOptions=月利润/关停成本/12月亏损/回本月数/综合分。
十六、页面14:平台与优惠管理 PlatformPage
单页面无Tab,2个API(全部GET),有MonthPicker。
核心数据源:analytics.mv_store_platform_economics_monthly、analytics.bill_fact。
API总览
| API |
数据源表 |
说明 |
| /platform/economics |
mv_store_platform_economics_monthly |
门店三平台经济性数据 |
| /marketing/plans |
bill_fact |
营销方案聚合分析 |
Block1:平台概览
API: /platform/economics
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 平台总实收 |
totalPlatformReceived |
— |
前端聚合:Σ(meituan+taobao+jd) |
mv_store_platform_economics_monthly |
| 合并加权成本率 |
blendedCostRate |
— |
前端计算:(Σ折扣+Σ佣金) / Σ实收 × 100 |
同上 |
| 高成本门店 |
highCostStores.length |
— |
前端过滤:任一平台cost_rate≥38% |
同上 |
| 营销方案数 |
marketingRows.length |
— |
来自/marketing/plans |
bill_fact |
后端 SELECT * 返回全字段,前端聚合计算。无分页,全量返回。
平台字段:meituan_received/discount/commission/cost_rate_pct、taobao_*、jd_*。
Block2:三平台对比图
BarChart:美团/淘宝/京东三组,每组3条柱(实收/折扣/佣金)。前端聚合 storesWithPlatform 数据。
Block3:门店平台经济性明细
FilterableTable:filterKey=store_name, sortOptions=美团实收/美团成本率/淘宝实收/京东实收/门店。
成本率颜色:≥38%红色, 35-38%黄色, <35%绿色。
经济性最优列:前端计算三平台中成本率最低的平台,显示名称和与最高的差距。
Block4:营销方案ROI
API: /marketing/plans
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 营销方案 |
r.marketing_plan |
marketing_plan |
— |
bill_fact |
| 账单数 |
r.bill_count |
bill_count |
count(*) |
同上 |
| 消费额 |
r.consumption |
consumption |
sum(consumption) |
同上 |
| 优惠额 |
r.discounts |
discounts |
sum(discount_total) |
同上 |
| 实收 |
r.received |
received |
sum(received_total) |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
avg(received_total) |
同上 |
| 优惠率 |
r.discount_rate_pct |
discount_rate_pct |
sum(discount_total)/sum(consumption)×100 |
— |
| 理论毛利率 |
r.theoretical_margin_pct |
theoretical_margin_pct |
sum(theoretical_profit)/sum(received_total)×100 |
— |
前端Top5营销方案卡片展示 + FilterableTable完整列表。
优惠率颜色:≥25%红色, 15-25%黄色, <15%绿色。
毛利率颜色:≥70%绿色, 60-70%黄色, <60%红色。
十七、页面15:营收分析 RevenuePage
单页面无Tab,4个API(全部GET),有MonthPicker。
核心数据源:analytics.v_store_daily、analytics.v_channel_daily、analytics.v_meal_period_daily。
API总览
| API |
数据源表 |
说明 |
| /revenue/daily-summary |
v_store_daily |
日度营收汇总(全门店合计) |
| /revenue/channel |
v_channel_daily |
渠道日度收入结构 |
| /revenue/meal-period |
v_meal_period_daily |
时段收入分布 |
| /revenue/store-ranking |
v_store_daily |
门店营收排名 |
Block1:核心指标
API: /revenue/daily-summary
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
totalConsumption |
— |
前端聚合:Σ consumption |
v_store_daily |
| 优惠总额 |
totalDiscounts |
— |
前端聚合:Σ discounts |
同上 |
| 实收总额 |
totalReceived |
— |
前端聚合:Σ received |
同上 |
| 账单数 |
totalBills |
— |
前端聚合:Σ bill_count |
同上 |
| 客单价 |
avgBillValue |
— |
前端计算:totalReceived / totalBills |
— |
| 优惠率 |
avgDiscountRate |
— |
前端计算:totalDiscounts / (totalReceived + totalDiscounts) × 100 |
— |
| 客流量 |
totalGuests |
— |
前端聚合:Σ guests |
v_store_daily |
| 人均消费 |
avgGuestValue |
— |
前端计算:totalReceived / totalGuests |
— |
后端SQL:sum(received + discounts) AS consumption, sum(received) AS received, sum(discounts) AS discounts, sum(bill_count), sum(guests),按 business_date 分组。
环比趋势:前端计算 last7 vs prev7 的实收和账单数环比。
Block2:日度营收趋势
ComposedChart:Bar(received) + Line(avg_bill) + Line(discount_rate),双Y轴。
X轴 business_date.substring(5, 10) ✅。
Block3:渠道收入结构 + 渠道趋势
API: /revenue/channel
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
|
| 微信 |
channelTotals.wechat |
wechat |
v_channel_daily |
|
| 支付宝 |
channelTotals.alipay |
alipay |
同上 |
|
| 美团外卖 |
channelTotals.meituan_delivery |
meituan_delivery |
同上 |
|
| 美团堂食 |
channelTotals.meituan |
meituan |
同上 |
|
| 淘宝外卖 |
channelTotals.taobao_delivery |
taobao_delivery |
同上 |
|
| 抖音 |
channelTotals.douyin |
douyin |
同上 |
|
| 现金 |
channelTotals.cash |
cash |
同上 |
|
| 京东外卖 |
channelTotals.jd_delivery |
jd_delivery |
同上 |
|
| 银联 |
channelTotals.unionpay |
unionpay |
同上 |
|
| 挂账 |
channelTotals.credit |
credit |
同上 |
|
PieChart(渠道占比) + LineChart(前5大渠道日度趋势)。
前端聚合日度数据为渠道总量,按值排序。
Block4:时段收入分布
API: /revenue/meal-period
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 餐段 |
r.meal_period |
meal_period |
— |
v_meal_period_daily |
| 账单数 |
r.bill_count |
bill_count |
sum(bill_count) |
同上 |
| 实收 |
r.received |
received |
sum(received) |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
sum(received)/sum(bill_count) |
— |
PieChart + 卡片列表展示各餐段收入和占比。
Block5:门店营收排名
API: /revenue/store-ranking
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 门店 |
r.store_name |
store_name |
— |
v_store_daily |
| 实收 |
r.received |
received |
sum(received) |
同上 |
| 账单数 |
r.bill_count |
bill_count |
sum(bill_count) |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
sum(received)/sum(bill_count) |
— |
| 优惠率 |
r.avg_discount_rate_pct |
avg_discount_rate_pct |
sum(discounts)/(sum(received)+sum(discounts))×100 |
— |
| 客流量 |
r.guests |
guests |
sum(guests) |
同上 |
| 理论毛利率 |
r.avg_theoretical_margin_pct |
avg_theoretical_margin_pct |
avg(theoretical_margin_pct) |
同上 |
TOP10/BOTTOM10 水平BarChart(点击跳转门店详情) + FilterableTable完整列表。
优惠率颜色:>25%红色, >20%黄色。
后端 ORDER BY sum(received) DESC,前端 slice(0,10) 和 slice(-10).reverse()。
十八、页面16:区域经理工作台 RegionalPage
单页面无Tab,5个API(4 GET + 1 PUT mutation),有MonthPicker。
核心数据源:analytics.mv_store_risk_rating_monthly、analytics.mv_store_action_priority_deep_monthly、analytics.mv_store_benchmark_composite_monthly、analytics.bill_fact、analytics.dim_store、analytics.v_task_weekly_check、analytics.store_task、analytics.task_weekly_check。
API总览
| API |
方法 |
数据源表 |
说明 |
| /stores/risk |
GET |
mv_store_risk_rating_monthly |
门店风险分级列表 |
| /stores/priority |
GET |
mv_store_action_priority_deep_monthly |
门店行动优先级 |
| /benchmark/composite |
GET |
mv_store_benchmark_composite_monthly |
同类门店基准对比 |
| /region/summary |
GET |
bill_fact + dim_store + mv_store_risk_rating_monthly |
区域经营汇总 |
| /tasks/weekly-check |
GET |
v_task_weekly_check |
周检任务列表 |
| /tasks/:id/weekly-check |
PUT |
store_task + store_task_log + task_weekly_check |
周检录入 |
Block1:汇总卡片
| 显示指标 |
前端变量 |
数据来源 |
计算公式 |
| 营业收入 |
Σ regionRows.total_consumption |
/region/summary |
前端聚合 |
| 优惠 |
Σ regionRows.total_discount |
同上 |
前端聚合 |
| 实收 |
Σ regionRows.total_received |
同上 |
前端聚合 |
| 红黄门店数 |
riskRows.filter(risk_level !== '绿色').length |
/stores/risk |
前端过滤 |
| P0+P1门店 |
p0p1.length |
/stores/priority |
前端过滤 action_priority.startsWith('P0'/'P1') |
| 需到店检查 |
needCheck.length |
/tasks/weekly-check |
前端过滤 consecutive_no_improve_weeks ≥ 2 |
| 周检待录入 |
weeklyRows.filter(!last_check_date).length |
同上 |
前端过滤 |
Block2:区域经营汇总
API: /region/summary
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 区域 |
r.region |
region |
— |
dim_store |
| 门店数 |
r.store_count |
store_count |
count(DISTINCT store_code) |
bill_fact |
| 营业收入 |
r.total_consumption |
total_consumption |
sum(consumption) |
同上 |
| 优惠 |
r.total_discount |
total_discount |
sum(discount_total) |
同上 |
| 实收 |
r.total_received |
total_received |
sum(received_total) |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
avg(received_total) |
同上 |
| 优惠率 |
r.avg_discount_rate |
avg_discount_rate |
sum(discount_total)/sum(consumption)×100 |
— |
| 毛利率 |
r.avg_margin_rate |
avg_margin_rate |
sum(theoretical_profit)/sum(received_total)×100 |
— |
| 异常率 |
r.avg_anomaly_rate |
avg_anomaly_rate |
硬编码 0 |
— |
| 红数 |
r.red_count |
red_count |
count(DISTINCT CASE WHEN risk_level='红色') |
mv_store_risk_rating_monthly |
| 黄数 |
r.yellow_count |
yellow_count |
同上黄色 |
同上 |
| 绿数 |
r.green_count |
green_count |
同上绿色 |
同上 |
FilterableTable,sortOptions=区域/营业收入/优惠/实收/客单价/门店数。
数据权限:使用 getDataScope(req) + scopeStoreFilter 实现区域经理只能看自己区域。
Block3:门店风险分级
API: /stores/risk
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店 |
r.store_name |
store_name |
mv_store_risk_rating_monthly |
| 风险 |
r.risk_level |
risk_level |
同上 |
| 实收 |
r.received |
received |
同上 |
| 优惠率 |
r.discount_rate_pct |
discount_rate_pct |
同上 |
| 毛利率 |
r.theoretical_margin_pct |
theoretical_margin_pct |
同上 |
| 异常率 |
r.anomaly_rate_pct |
anomaly_rate_pct |
同上 |
后端 SELECT * + ORDER BY risk_level, received DESC。前端风险筛选按钮(全部/红色/黄色/绿色)+ FilterableTable。
点击行跳转 /stores/:store_code。
Block4:需到店检查门店
API: /tasks/weekly-check
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店 |
r.store_name |
store_name |
v_task_weekly_check |
| 问题指标 |
r.problem_indicator |
problem_indicator |
同上 |
| 连续未改善周数 |
r.consecutive_no_improve_weeks |
consecutive_no_improve_weeks |
同上 |
| 任务状态 |
r.status |
status |
同上 |
前端过滤 consecutive_no_improve_weeks ≥ 2。点击"录入周检"打开弹窗。
PUT API:/tasks/:id/weekly-check,更新 store_task.process_evidence/next_step,插入 store_task_log 和 task_weekly_check 记录。
Block5:同类门店基准对比
API: /benchmark/composite
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店 |
r.store_name |
store_name |
mv_store_benchmark_composite_monthly |
| 标杆得分 |
r.benchmark_score |
benchmark_score |
同上 |
| 实收 |
r.received |
received |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
同上 |
| 优惠率 |
r.discount_rate_pct |
discount_rate_pct |
同上 |
| 毛利率 |
r.theoretical_margin_pct |
theoretical_margin_pct |
同上 |
| 会员占比 |
r.member_bill_share_pct |
member_bill_share_pct |
同上 |
后端 SELECT * ORDER BY benchmark_score DESC。标杆得分颜色:≥80绿色, ≥60黄色, <60红色。
十九、页面17:门店选址分析 SiteSelectionPage
单页面4个Tab(分段基准/复制评分/重叠风险/区域基准),5个API(全部GET),有MonthPicker。
核心数据源:analytics.mv_store_site_profile_monthly、analytics.mv_site_segment_benchmark_monthly、analytics.mv_store_site_replication_monthly、analytics.mv_store_overlap_risk_monthly、analytics.mv_district_site_benchmark_monthly。
API总览
| API |
Tab |
数据源表 |
说明 |
| /site-selection/profile |
全局 |
mv_store_site_profile_monthly |
门店选址画像 |
| /site-selection/segment-benchmark |
分段基准 |
mv_site_segment_benchmark_monthly |
场景×面积分段基准 |
| /site-selection/replication |
复制评分 |
mv_store_site_replication_monthly |
门店复制评分 |
| /site-selection/overlap-risk |
重叠风险 |
mv_store_overlap_risk_monthly |
门店空间重叠风险 |
| /site-selection/district-benchmark |
区域基准 |
mv_district_site_benchmark_monthly |
区域选址基准 |
全局:概览指标 + 散点图 + 地图
API: /site-selection/profile
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 标准门店数 |
profileRows.length |
— |
mv_store_site_profile_monthly |
| 场景类型数 |
totalScenes |
— |
前端聚合 site_scene 去重 |
| 高风险重叠对 |
highRiskCount |
— |
来自 /overlap-risk 前端过滤 |
| 优先提炼原型 |
topReplication |
— |
来自 /replication 前端过滤 |
StoreMap:自定义地图组件,按场景类型颜色标注门店位置。
ScatterChart:X=面积(㎡), Y=月坪效(元/㎡), Z=实收(气泡大小),按场景颜色区分。
后端 WHERE business_type='标准门店' AND received>0,ORDER BY received DESC。
Tab1:分段基准(benchmark)
API: /site-selection/segment-benchmark
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 场景 |
r.site_scene |
site_scene |
mv_site_segment_benchmark_monthly |
| 面积段 |
r.area_band |
area_band |
同上 |
| 门店数 |
r.store_count |
store_count |
同上 |
| 平均面积 |
r.avg_area_sqm |
avg_area_sqm |
同上 |
| 平均实收 |
r.avg_received |
avg_received |
同上 |
| 中位实收 |
r.median_received |
median_received |
同上 |
| 平均坪效 |
r.avg_received_per_sqm |
avg_received_per_sqm |
同上 |
| 中位坪效 |
r.median_received_per_sqm |
median_received_per_sqm |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
同上 |
| 复购率 |
r.avg_repeat_rate_pct |
avg_repeat_rate_pct |
同上 |
FilterableTable,filterKey=site_scene,sortOptions=平均坪效/中位坪效/平均实收/场景。
后端 ORDER BY avg_received_per_sqm DESC。
门店画像明细:同 profile API 数据,filterKey=site_scene,点击行跳转门店详情。
Tab2:复制评分(replication)
API: /site-selection/replication
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店 |
r.store_name |
store_name |
mv_store_site_replication_monthly |
| 场景 |
r.site_scene |
site_scene |
同上 |
| 面积 |
r.area_sqm |
area_sqm |
同上 |
| 实收 |
r.received |
received |
同上 |
| 坪效 |
r.monthly_received_per_sqm |
monthly_received_per_sqm |
同上 |
| 最近门店 |
r.nearest_store_name |
nearest_store_name |
同上 |
| 距离 |
r.nearest_distance_km |
nearest_distance_km |
同上 |
| 复制评分 |
r.site_replication_score |
site_replication_score |
同上 |
| 复制建议 |
r.replication_recommendation |
replication_recommendation |
同上 |
| 空间建议 |
r.spatial_recommendation |
spatial_recommendation |
同上 |
FilterableTable,filterKey=replication_recommendation,sortOptions=复制评分/实收/坪效/距离。
复制评分颜色:≥75绿色, ≥60蓝色, <40红色。
复制建议标签:优先提炼选址原型(绿)、不宜作为选址标杆(红)、其他(蓝)。
后端 ORDER BY site_replication_score DESC。
Tab3:重叠风险(overlap)
API: /site-selection/overlap-risk
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店A |
r.store_name_a |
store_name_a |
mv_store_overlap_risk_monthly |
| 门店B |
r.store_name_b |
store_name_b |
同上 |
| 距离 |
r.distance_km |
distance_km |
同上 |
| A实收 |
r.received_a |
received_a |
同上 |
| B实收 |
r.received_b |
received_b |
同上 |
| 风险等级 |
r.overlap_risk |
overlap_risk |
同上 |
3个MetricCard(<1km/1-2km/2-3km)+ FilterableTable。
filterKey=overlap_risk,sortOptions=距离/A实收/B实收。
后端 ORDER BY distance_km。
Tab4:区域基准(district)
API: /site-selection/district-benchmark
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 区域 |
r.district |
district |
mv_district_site_benchmark_monthly |
| 门店数 |
r.store_count |
store_count |
同上 |
| 平均面积 |
r.avg_area_sqm |
avg_area_sqm |
同上 |
| 总实收 |
r.total_received |
total_received |
同上 |
| 平均实收 |
r.avg_received |
avg_received |
同上 |
| 中位实收 |
r.median_received |
median_received |
同上 |
| 平均坪效 |
r.avg_received_per_sqm |
avg_received_per_sqm |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
同上 |
| 复购率 |
r.avg_repeat_rate_pct |
avg_repeat_rate_pct |
同上 |
| P0数 |
r.p0_count |
p0_count |
同上 |
| P1数 |
r.p1_count |
p1_count |
同上 |
BarChart(前15区域平均/中位实收对比) + FilterableTable。
sortOptions=平均实收/平均坪效/总实收/区域。
后端 ORDER BY total_received DESC。
二十、页面18:时间维度分析 TimePage
单页面无Tab,3个API(全部GET),有MonthPicker。
核心数据源:mv_time_weekday、mv_time_hourly、mv_channel_daily。
API总览
| API |
数据源表 |
说明 |
| /time/weekday |
mv_time_weekday |
星期维度分析 |
| /time/hourly |
mv_time_hourly |
小时维度分析 |
| /channel |
mv_channel_daily |
渠道日度趋势 |
Block1:时间概览
| 显示指标 |
前端变量 |
数据来源 |
计算公式 |
| 高峰日 |
peakWeekday.weekday |
/time/weekday |
前端 reduce 找最大 received |
| 低谷日 |
lowWeekday.weekday |
同上 |
前端 reduce 找最小 received |
| 高峰时段 |
peakHour.closing_hour |
/time/hourly |
前端 reduce 找最大 bill_count |
| 渠道数 |
channelTotals.length |
/channel |
前端聚合非零渠道数 |
Block2:星期维度分析
API: /time/weekday
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 星期 |
r.weekday |
weekday |
mv_time_weekday |
| 实收 |
r.received |
received |
同上 |
| 账单数 |
r.bill_count |
bill_count |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
同上 |
BarChart(实收+账单数)+ Line(客单价),双Y轴。后端 WHERE month = to_char($1::date, 'YYYY-MM')。
Block3:小时维度分析
API: /time/hourly
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 小时 |
r.closing_hour |
closing_hour |
mv_time_hourly |
| 账单数 |
r.bill_count |
bill_count |
同上 |
| 实收 |
r.received |
received |
同上 |
| 客单价 |
r.avg_bill_value |
avg_bill_value |
同上 |
AreaChart(实收+账单数),双Y轴。后端 WHERE month = to_char($1::date, 'YYYY-MM')。
Block4:渠道趋势 + 渠道汇总
API: /channel
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 日期 |
r.business_date |
business_date |
mv_channel_daily |
| 现金 |
r.cash |
cash |
同上 |
| 支付宝 |
r.alipay |
alipay |
同上 |
| 微信 |
r.wechat |
wechat |
同上 |
| 美团到店 |
r.meituan |
meituan |
同上 |
| 银联 |
r.unionpay |
unionpay |
同上 |
| 抖音 |
r.douyin |
douyin |
同上 |
| 挂账 |
r.credit |
credit |
同上 |
| 京东到家 |
r.jd_delivery |
jd_delivery |
同上 |
| 美团外卖 |
r.meituan_delivery |
meituan_delivery |
同上 |
| 淘宝外卖 |
r.taobao_delivery |
taobao_delivery |
同上 |
LineChart(前6大渠道日度趋势)+ 渠道汇总卡片。X轴 business_date.substring(5, 10) ✅。
注意:此API与 RevenuePage 的 /revenue/channel 数据源相同(mv_channel_daily),但查询无 schema 前缀(mv_channel_daily vs analytics.v_channel_daily)。
二十一、页面19:指标字典 IndicatorsPage
单页面无Tab,1个API(GET),无MonthPicker。
核心数据源:analytics.indicator_dictionary。
API: /tasks/indicators
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 指标名称 |
r.indicator_name |
indicator_name |
indicator_dictionary |
| 业务定义 |
r.business_definition |
business_definition |
同上 |
| 计算公式 |
r.formula |
formula |
同上 |
| 更新频率 |
r.update_frequency |
update_frequency |
同上 |
| 负责人 |
r.owner |
owner |
同上 |
| 黄线 |
r.yellow_threshold |
yellow_threshold |
同上 |
| 红线 |
r.red_threshold |
red_threshold |
同上 |
| 版本日期 |
r.version_date |
version_date |
同上 |
FilterableTable,filterKey=update_frequency,sortOptions=指标名称/更新频率/负责人。
version_date?.substring(0, 10) ✅。后端 SELECT * ORDER BY id,无分页。
二十二、页面20:任务管理 TasksPage
单页面无Tab,1个API(GET),有MonthPicker + 优先级/状态筛选。
核心数据源:analytics.store_task。
API: /tasks
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 问题指标 |
r.problem_indicator |
problem_indicator |
store_task |
| 行动要求 |
r.action_required |
action_required |
同上 |
| 负责人 |
r.owner |
owner |
同上 |
| 截止日 |
r.deadline?.substring(0,10) |
deadline |
同上 |
| 状态 |
r.status |
status |
同上 |
| 优先级 |
r.priority |
priority |
同上 |
| 门店 |
r.store_name |
store_name |
同上 |
| 门店编码 |
r.store_code |
store_code |
同上 |
后端支持分页(parsePagination),前端传 page_size: 200。
前端按 store_code 分组展示,每组内 FilterableTable。
筛选:priority + status 参数传递到后端 WHERE 条件。
deadline?.substring(0, 10) ✅。
二十三、页面21:任务详情 TaskDetailPage
单页面无Tab,2个API(1 GET + 1 GET indicators)+ 3个mutation(PUT execute, PUT verify, POST rollback)。
核心数据源:analytics.store_task、analytics.store_task_log、analytics.indicator_dictionary。
API: /tasks/:id (GET)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店名 |
task.store_name |
store_name |
store_task |
| 问题指标 |
task.problem_indicator |
problem_indicator |
同上 |
| 优先级 |
task.priority |
priority |
同上 |
| 状态 |
task.status |
status |
同上 |
| 当前值 |
task.current_value |
current_value |
同上 |
| 基准值 |
task.benchmark_value |
benchmark_value |
同上 |
| 目标值 |
task.target_value |
target_value |
同上 |
| 问题描述 |
task.problem_description |
problem_description |
同上 |
| 验收指标 |
task.verification_indicator |
verification_indicator |
同上 |
| 行动要求 |
task.action_required |
action_required |
同上 |
| 负责人 |
task.owner |
owner |
同上 |
| 截止日 |
task.deadline?.substring(0,10) |
deadline |
同上 |
| 过程证据 |
task.process_evidence |
process_evidence |
同上 |
| 未完成原因 |
task.incomplete_reason |
incomplete_reason |
同上 |
| 验收结果 |
task.verification_result |
verification_result |
同上 |
| 操作日志 |
logs |
— |
store_task_log |
后端 SELECT * FROM store_task WHERE task_id = $1 + SELECT * FROM store_task_log WHERE task_id = $1。
deadline?.substring(0, 10) ✅,log.created_at?.substring(0, 19) ✅。
Mutations
| Mutation |
API |
说明 |
| executeMutation |
PUT /tasks/:id/execute |
提交执行反馈,状态改为"进行中" |
| verifyMutation |
PUT /tasks/:id/verify |
月度验收,传 review_result/actual_value 等 |
| rollbackMutation |
POST /tasks/:id/rollback |
回滚任务 |
指标说明:从 /tasks/indicators 获取指标字典,匹配 problem_indicator 显示业务定义、计算公式、黄线/红线阈值。
二十四、页面22:月度验收与复盘 MonthlyReviewPage
7个Tab(验收汇总/升降级/任务完成率/活动清单/SKU治理/经验标准化/复盘优化),7个API(6 GET + 1 POST mutation),有MonthPicker。
核心数据源:analytics.v_task_monthly_review、analytics.store_grade_change、analytics.store_task、analytics.bill_fact、analytics.mv_dish_sku_abc_monthly、analytics.standardized_practice。
API总览
| API |
Tab |
数据源表 |
说明 |
| /tasks/monthly-review |
验收汇总 |
v_task_monthly_review |
验收汇总+明细 |
| /tasks/grade-change |
升降级 |
store_grade_change |
P0/P1/P2升降级 |
| /tasks/monthly-review/completion |
完成率 |
store_task |
按优先级汇总完成率 |
| /tasks/monthly-review/activity-list |
活动清单 |
bill_fact |
平台活动停/改/留 |
| /tasks/monthly-review/sku-governance |
SKU治理 |
mv_dish_sku_abc_monthly |
ABC分类+长尾清单 |
| /tasks/practices |
经验标准化 |
standardized_practice |
标准化经验列表 |
| POST /tasks/practices |
经验标准化 |
standardized_practice |
新增经验 |
Tab1:验收汇总
API: /tasks/monthly-review
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 总任务数 |
summary.total |
— |
后端计算 result.rows.length |
| 达标 |
summary.passed |
— |
后端 filter review_result='达标' |
| 改善中 |
summary.improving |
— |
同上 |
| 未改善 |
summary.failed |
— |
同上 |
| 门店 |
r.store_name |
store_name |
v_task_monthly_review |
| 问题指标 |
r.problem_indicator |
problem_indicator |
同上 |
| 基线 |
r.baseline_value |
baseline_value |
同上 |
| 目标 |
r.target_value |
target_value |
同上 |
| 实际 |
r.actual_value |
actual_value |
同上 |
| 结果 |
r.review_result |
review_result |
同上 |
PieChart(验收结果分布)+ FilterableTable。后端 SELECT * WHERE plan_month = $1。
Tab2:升降级面板
API: /tasks/grade-change
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 月份 |
r.change_month?.substring(0,7) |
change_month |
store_grade_change |
| 门店 |
r.store_name |
store_name |
同上 |
| 原级别 |
r.old_priority |
old_priority |
同上 |
| 新级别 |
r.new_priority |
new_priority |
同上 |
| 变化 |
r.change_type |
change_type |
同上 |
| 原因 |
r.reason |
reason |
同上 |
change_month?.substring(0, 7) ✅。后端 SELECT * WHERE change_month = $1::date。
Tab3:任务完成率
API: /tasks/monthly-review/completion
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 优先级 |
c.priority |
priority |
— |
store_task |
| 总数 |
c.total |
total |
count(*) |
同上 |
| 已完成 |
c.completed |
completed |
count FILTER(status='已验收'/'已回滚') |
同上 |
| 达标 |
c.passed |
passed |
count FILTER(verification_result='达标') |
同上 |
| 改善中 |
c.improving |
improving |
同上 |
同上 |
| 未改善 |
c.failed |
failed |
同上 |
同上 |
| 完成率 |
c.completion_rate |
completion_rate |
completed/total×100 |
同上 |
进度条卡片 + FilterableTable。后端 GROUP BY priority。
Tab4:活动清单
API: /tasks/monthly-review/activity-list
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 活动方案 |
r.marketing_plan |
marketing_plan |
— |
bill_fact |
| 账单数 |
r.bill_count |
bill_count |
count(*) |
同上 |
| 消费额 |
r.consumption |
consumption |
sum(consumption) |
同上 |
| 优惠额 |
r.discounts |
discounts |
sum(discount_total) |
同上 |
| 实收 |
r.received |
received |
sum(received_total) |
同上 |
| 优惠成本率 |
r.discount_cost_rate |
discount_cost_rate |
discounts/consumption×100 |
— |
| 净贡献 |
r.net_contribution |
net_contribution |
received - discounts |
— |
| 建议 |
前端计算 |
— |
net>0 && rate<15→留, rate>30→停, else→改 |
— |
FilterableTable,sortOptions=净贡献/实收/优惠成本率/账单数。
Tab5:SKU治理
API: /tasks/monthly-review/sku-governance
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| ABC分类 |
s.abc_class |
abc_class |
mv_dish_sku_abc_monthly |
| SKU数 |
s.sku_count |
sku_count |
同上 |
| 营收占比 |
s.total_revenue_share |
total_revenue_share |
同上 |
| 菜品名 |
r.dish_name |
dish_name |
同上(C类) |
| 分类 |
r.category_level1 |
category_level1 |
同上 |
| 账单数 |
r.bill_count |
bill_count |
同上 |
| 实收 |
r.received_amount |
received_amount |
同上 |
| 营收占比 |
r.revenue_share_pct |
revenue_share_pct |
同上 |
后端返回 { summary, longtail },longtail LIMIT 50。
Tab6:经验标准化
API: /tasks/practices (GET + POST)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 模块 |
p.practice_module |
practice_module |
standardized_practice |
| 标杆门店 |
p.benchmark_store_name |
benchmark_store_name |
同上 |
| 关键动作 |
p.key_actions |
key_actions |
同上 |
| 状态 |
p.status |
status |
同上 |
POST 新增经验,字段 practice_module/benchmark_store_code/benchmark_store_name/key_actions/verification_indicators。
Tab7:复盘优化
API: /tasks/monthly-review/indicator-effectiveness
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 指标 |
r.problem_indicator |
problem_indicator |
— |
store_task |
| 任务数 |
r.task_count |
task_count |
count(*) |
同上 |
| 达标 |
r.passed |
passed |
count FILTER(verification_result='达标') |
同上 |
| 改善中 |
r.improving |
improving |
同上 |
同上 |
| 未改善 |
r.failed |
failed |
同上 |
同上 |
| 达标率 |
r.pass_rate |
pass_rate |
passed/task_count×100 |
— |
| 评价 |
前端计算 |
— |
≥50%有效, ≥30%待观察, <30%低效 |
— |
后端 GROUP BY problem_indicator ORDER BY pass_rate DESC。
二十五、页面23:数据质量看板 DataQualityPage
单页面无Tab,1个API(GET),有MonthPicker。
核心数据源:analytics.bill_fact、public.dish_sales_details、analytics.mv_inventory_cost_classified_monthly。
API: /data-quality
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 总账单数 |
totalBills |
total_bills |
count(*) |
bill_fact |
| 覆盖门店数 |
storeCount |
store_count |
count(DISTINCT store_code) |
同上 |
| 缺失账单号 |
missingBillNo |
missing_bill_no |
count FILTER(bill_no IS NULL/='') |
同上 |
| 缺失门店编码 |
missingStoreCode |
missing_store_code |
同上 |
同上 |
| 零消费账单 |
zeroConsumption |
zero_consumption |
count FILTER(consumption=0/NULL) |
同上 |
| 负实收账单 |
negativeReceived |
negative_received |
count FILTER(received_total<0) |
同上 |
| 零实收账单 |
zeroReceived |
zero_received |
count FILTER(received_total=0/NULL) |
同上 |
| 优惠大于消费 |
discountGtConsumption |
discount_gt_consumption |
count FILTER(discount_total>consumption AND consumption>0) |
同上 |
| 日期范围 |
dq.min_date?.substring(0,10) |
min_date/max_date |
min/max(closed_at) |
同上 |
| 总菜品记录数 |
totalDishRecords |
total_dish_records |
count(*) |
dish_sales_details |
| 缺失门店(菜品) |
dishMissingStore |
dish_missing_store |
count FILTER(store_code IS NULL/='') |
同上 |
| 缺失菜品名 |
dishMissingDish |
dish_missing_dish |
count FILTER(dish_name IS NULL/='') |
同上 |
| 负耗用记录数 |
negativeConsumptionCount |
negative_consumption_count |
count FILTER(consumption_amount<0) |
mv_inventory_cost_classified_monthly |
| 负耗用金额 |
negativeConsumptionAmount |
negative_consumption_amount |
sum(consumption_amount) FILTER(<0) |
同上 |
注意:账单和菜品统计无月份过滤(全量扫描),仅库存统计按 month_start 过滤。
min_date/max_date?.substring(0, 10) ✅。
四层状态:完整性/准确性/一致性/时效性,前端根据指标值计算。
置信等级:A(正常)/B(待桥接)/C(异常)。
二十六、页面24:银行授信数据报告 BankPage
单页面无Tab,1个API(GET),有MonthPicker + 评分规则配置面板。
核心数据源:analytics.mv_overview_monthly、analytics.mv_overview_daily、analytics.bill_fact、analytics.mv_store_operating_expense_monthly、analytics.mv_store_risk_rating_monthly、analytics.v_channel_daily。
API: /bank/report
后端 Promise.all 并发6个查询,返回 { overview, daily, waterfall, risk, channel, stores, stability }。
Block1:银行授信评估摘要
| 评分指标 |
前端变量 |
数据来源 |
计算公式 |
| 净利率 |
metrics.netMargin |
waterfall |
store_contribution/received×100 |
| 营收稳定性 |
metrics.cv |
stability |
stdDev/meanDailyRevenue |
| 门店健康度 |
metrics.redPct |
risk |
红色门店数/总门店数×100 |
| 规模体量 |
metrics.scale |
overview |
ov.received |
| 优惠率 |
metrics.discountRate |
overview |
ov.discount_rate_pct |
| 会员占比 |
metrics.memberShare |
overview |
ov.member_share_pct |
评分规则:可配置权重和阈值,localStorage 持久化。单项得分 0-100,加权总分 → 信用等级 A(≥85)/B(≥70)/C(≥50)/D(<50)。
Block2:企业经营概况
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 营业收入 |
wf.consumption |
waterfall.consumption |
bill_fact |
| 优惠 |
wf.discount |
waterfall.discount |
同上 |
| 月度实收 |
ov.received |
overview.received |
mv_overview_monthly |
| 客单价 |
ov.avg_bill_value |
overview.avg_bill_value |
同上 |
| 理论毛利率 |
ov.theoretical_margin_pct |
overview.theoretical_margin_pct |
同上 |
| 门店数量 |
stores.length |
— |
mv_store_risk_rating_monthly |
| 日实收趋势 |
dailyChart |
daily |
mv_overview_daily |
business_date?.substring(5, 10) ✅。
Block3:盈利能力分析(利润瀑布)
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 营业收入 |
wf.consumption |
consumption |
sum(consumption) |
bill_fact |
| 优惠 |
wf.discount |
discount |
sum(discount_total) |
同上 |
| 实收 |
wf.received |
received |
sum(received) |
mv_store_risk_rating_monthly |
| 食材 |
wf.food_cost |
food_cost |
sum(actual_food_cost) |
mv_store_operating_expense_monthly |
| 人工 |
wf.wage |
wage |
sum(wage_expense) |
同上 |
| 房租 |
wf.rent |
rent |
sum(rent_expense) |
同上 |
| 水电 |
wf.utility |
utility |
sum(utility_expense) |
同上 |
| 其他 |
wf.dorm+commission+other |
dorm/commission/other_expense |
sum(dorm+commission+card_fee+repair) |
同上 |
| 门店贡献利润 |
wf.store_contribution |
store_contribution |
received - food_cost - operating_expense |
— |
自定义 BarChart shape 实现瀑布图效果。
Block4:门店资产质量
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 风险分布 |
riskPie |
risk |
mv_store_risk_rating_monthly |
| TOP10门店 |
top10 |
stores |
同上 |
PieChart(风险等级分布)+ 横向 BarChart(TOP10门店实收)。
Block5:经营稳定性指标
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 日度营收波动率 |
stability.cv |
stability.cv |
stdDev/mean |
mv_overview_daily |
| 日均收入 |
stability.mean_daily_revenue |
stability.mean_daily_revenue |
— |
同上 |
| 优惠率 |
ov.discount_rate_pct |
overview.discount_rate_pct |
— |
mv_overview_monthly |
| 会员消费占比 |
ov.member_share_pct |
overview.member_share_pct |
— |
同上 |
| 活跃渠道数 |
channelPie.length |
channel |
前端非零渠道数 |
v_channel_daily |
渠道 PieChart,标签显示渠道名称和占比。
二十七、页面25:本体标准 OntologyPage
5个Tab(概览/维度主数据/事实表/枚举标准/指标标准),5个API(全部GET),无MonthPicker。
核心数据源:information_schema.columns、analytics.indicator_dictionary、各 dim_/fact_/enum_ 表。
API总览
| API |
Tab |
数据源 |
说明 |
| /tasks/ontology/overview |
概览 |
information_schema + indicator_dictionary |
表统计概览 |
| /tasks/ontology/dim/:table |
维度主数据 |
对应 dim_ 表 |
维度表数据+字段定义 |
| /tasks/ontology/fact/:table |
事实表 |
对应 fact_ 表 |
事实表字段定义 |
| /tasks/ontology/enum/:table |
枚举标准 |
对应 enum_ 表 |
枚举值列表 |
| /tasks/ontology/metrics |
指标标准 |
indicator_dictionary |
指标字典 |
Tab1:概览
显示维度表数、事实表数、枚举表数、指标标准数。点击可跳转到对应Tab。
Tab2-4:维度/事实/枚举
列表→详情模式。列表显示表名、字段数、行数。点击进入详情,FilterableTable 展示数据(pageSize=20),下方显示字段定义表。
后端使用正则校验表名 ^dim_\w+$ / ^fact_\w+$ / ^enum_\w+$ 防注入。
时间戳字段 String(val).substring(0, 19) ✅。
Tab5:指标标准
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 指标编码 |
r.metric_code |
metric_code |
indicator_dictionary |
| 指标名称 |
r.indicator_name |
indicator_name |
同上 |
| 分类 |
r.metric_category |
metric_category |
同上 |
| 业务定义 |
r.business_definition |
business_definition |
同上 |
| 计算公式 |
r.formula |
formula |
同上 |
| 单位 |
r.unit |
unit |
同上 |
| 方向 |
r.direction |
direction |
同上 |
| 负责人 |
r.owner |
owner |
同上 |
| 黄线 |
r.yellow_threshold |
yellow_threshold |
同上 |
| 红线 |
r.red_threshold |
red_threshold |
同上 |
| 更新频率 |
r.update_frequency |
update_frequency |
同上 |
| 版本 |
r.version |
version |
同上 |
前端分类筛选(全部/收入/成本/优惠/会员/商品/库存/风险)+ FilterableTable。
二十八、页面26:中央厨房成本驾驶舱 CentralKitchenPage
单页面无Tab,1个API(GET),有MonthPicker。
核心数据源:analytics.v_central_kitchen_product_full_cost、central_kitchen_processing_cost、central_kitchen_recipe_consumption、central_kitchen_manufacturing_cost_pool、central_kitchen_finished_receipt。
API: /central-kitchen/dashboard
后端 Promise.all 并发7个查询,返回 { summary, reconciliation, products, categoryCost, recipeEfficiency, mfgPool, yieldAnalysis }。
Block1:核心指标卡片
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 产品数 |
summary.product_count |
product_count |
count(*) |
v_central_kitchen_product_full_cost |
| 完工入库量 |
summary.total_inbound_qty |
total_inbound_qty |
sum(inbound_quantity) |
同上 |
| 理论材料成本 |
summary.theoretical_cost |
theoretical_cost |
sum(theoretical_cost) |
同上 |
| 实际材料成本 |
summary.material_actual_cost |
material_actual_cost |
sum(material_actual_cost) |
同上 |
| 完整制造成本 |
summary.full_manufacturing_cost |
full_manufacturing_cost |
sum(full_manufacturing_cost) |
同上 |
| 材料效率差异 |
summary.efficiency_variance_pct |
efficiency_variance_pct |
(实际-理论)/理论×100 |
— |
| 制造费用率 |
summary.mfg_cost_rate |
mfg_cost_rate |
制造费用池/实际材料×100 |
— |
后端 WHERE report_month = $1::date。
Block2:成本对账瀑布
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 理论成本 |
reconciliation.theoretical_cost |
theoretical_cost |
v_central_kitchen_product_full_cost |
| 标准成本 |
reconciliation.standard_cost |
standard_cost |
同上 |
| 实际材料 |
reconciliation.material_actual_cost |
material_actual_cost |
同上 |
| 制造费用池 |
reconciliation.manufacturing_cost_pool |
manufacturing_cost_pool |
同上 |
| 全制造成本 |
reconciliation.full_manufacturing_cost |
full_manufacturing_cost |
同上 |
| 入库价值 |
reconciliation.calculated_inbound_value |
calculated_inbound_value |
central_kitchen_processing_cost |
| 制造毛利 |
reconciliation.manufacturing_margin |
manufacturing_margin |
入库价值-全制造成本 |
后端 JOIN central_kitchen_processing_cost c ON p.report_month = c.report_month AND p.product_code = c.product_code。
自定义 BarChart shape 实现瀑布图效果。
Block3:品类成本结构
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 品类 |
c.category_minor |
category_minor |
v_central_kitchen_product_full_cost |
| 产品数 |
c.product_count |
product_count |
同上 |
| 入库量 |
c.total_qty |
total_qty |
同上 |
| 理论成本 |
c.theoretical_cost |
theoretical_cost |
同上 |
| 实际材料 |
c.material_actual_cost |
material_actual_cost |
同上 |
| 制造费用 |
c.allocated_mfg_cost |
allocated_mfg_cost |
同上 |
| 全成本 |
c.full_cost |
full_cost |
同上 |
| 效率差异 |
c.efficiency_var_pct |
efficiency_var_pct |
同上 |
堆叠 BarChart(材料成本+制造费用)+ FilterableTable。后端 GROUP BY category_minor ORDER BY full_cost DESC。
Block4:产品成本偏差散点图
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 产品名 |
p.product_name |
product_name |
v_central_kitchen_product_full_cost |
| 理论成本(X) |
p.theoretical_cost |
theoretical_cost |
同上 |
| 实际成本(Y) |
p.material_actual_cost |
material_actual_cost |
同上 |
| 偏差率(颜色) |
p.efficiency_variance_pct |
efficiency_variance_pct |
同上 |
ScatterChart,颜色按偏差率分4档:节约(≤-5%)/正常(-5%0%)/轻微超耗(05%)/严重超耗(≥5%)。
Block5:产品成本明细表
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 编码 |
p.product_code |
product_code |
v_central_kitchen_product_full_cost |
| 产品名 |
p.product_name |
product_name |
同上 |
| 品类 |
p.category_minor |
category_minor |
同上 |
| 入库量 |
p.inbound_quantity |
inbound_quantity |
同上 |
| 理论成本 |
p.theoretical_cost |
theoretical_cost |
同上 |
| 标准成本 |
p.standard_cost |
standard_cost |
同上 |
| 实际材料 |
p.material_actual_cost |
material_actual_cost |
同上 |
| 制造费用 |
p.allocated_manufacturing_cost |
allocated_manufacturing_cost |
同上 |
| 全成本 |
p.full_manufacturing_cost |
full_manufacturing_cost |
同上 |
| 单位成本 |
p.full_unit_cost |
full_unit_cost |
同上 |
| 效率差异 |
p.efficiency_variance_pct |
efficiency_variance_pct |
同上 |
| 标准差异 |
p.standard_variance_pct |
standard_variance_pct |
同上 |
| 入库价值 |
p.inbound_value |
inbound_value |
central_kitchen_processing_cost |
| 产品毛利 |
p.product_margin |
product_margin |
入库价值-全制造成本 |
FilterableTable,searchKeys=product_code/product_name/category_minor。后端 ORDER BY p.full_manufacturing_cost DESC。
Block6:配方效率分析 TOP20
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 配方 |
r.recipe_name |
recipe_name |
central_kitchen_recipe_consumption |
| 物料 |
r.item_name |
item_name |
同上 |
| 规格 |
r.specification |
specification |
同上 |
| 理论用量 |
r.theoretical_qty |
theoretical_qty |
同上 |
| 实际用量 |
r.actual_qty |
actual_qty |
同上 |
| 理论金额 |
r.theoretical_amt |
theoretical_amt |
同上 |
| 实际金额 |
r.actual_amt |
actual_amt |
同上 |
| 差异率 |
r.variance_pct |
variance_pct |
同上 |
| 实际出成率 |
r.avg_actual_yield |
avg_actual_yield |
同上 |
| 标准出成率 |
r.avg_recipe_yield |
avg_recipe_yield |
同上 |
| 出成差异 |
r.yield_diff |
yield_diff |
同上 |
后端 WHERE business_date >= $1 AND business_date < ($1 + INTERVAL '1 month'),GROUP BY recipe_name, item_name, specification, unit,LIMIT 20。
Block7:出成率分析 TOP20
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 配方 |
y.recipe_name |
recipe_name |
central_kitchen_finished_receipt |
| 产品名 |
y.product_name |
product_name |
同上 |
| 理论入库量 |
y.theoretical_inbound_qty |
theoretical_inbound_qty |
同上 |
| 实际入库量 |
y.actual_inbound_qty |
actual_inbound_qty |
同上 |
| 达成率 |
y.avg_achievement_rate |
avg_achievement_rate |
同上 |
| 预期偏差率 |
y.avg_expected_var_rate |
avg_expected_var_rate |
同上 |
| 入库金额 |
y.total_inbound_amt |
total_inbound_amt |
同上 |
| 退库量 |
y.total_return_qty |
total_return_qty |
同上 |
| 退库率 |
y.return_rate |
return_rate |
同上 |
后端 WHERE receipt_date >= $1 AND receipt_date < ($1 + INTERVAL '1 month'),LIMIT 20。
Block8:制造费用池明细
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 费用类型 |
m.cost_type |
cost_type |
central_kitchen_manufacturing_cost_pool |
| 费用子类 |
m.cost_subtype |
cost_subtype |
同上 |
| 来源 |
m.source_type |
source_type |
同上 |
| 原始金额 |
m.source_amount |
source_amount |
同上 |
| 分摊比例 |
m.share_pct |
share_pct |
同上 |
| 分摊金额 |
m.allocated_amount |
allocated_amount |
同上 |
| 分摊方法 |
m.allocation_method |
allocation_method |
同上 |
| 计入重建 |
m.include_in_rebuilt_cost |
include_in_rebuilt_cost |
同上 |
| 临时 |
m.is_provisional |
is_provisional |
同上 |
后端 WHERE report_month = $1::date ORDER BY include_in_rebuilt_cost DESC, allocated_amount DESC。
二十九、页面27:配送—倒挤成本对账 DistributionReconciliationPage
单页面无Tab,1个API(GET),有MonthPicker。
核心数据源:mv_distribution_monthly、analytics.fact_inventory_snapshot。
API: /distribution/reconciliation
后端先检查 mv_distribution_monthly 是否包含当月数据,如缺失则 REFRESH MATERIALIZED VIEW CONCURRENTLY。然后 Promise.all 并发5个查询,返回 { summary, storeReconciliation, topVariances, unmatchedItems, categoryReconciliation }。
Block1:核心指标卡片
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 对账品项行 |
summary.total_lines |
total_lines |
count(*) |
mv_distribution_monthly + fact_inventory_snapshot |
| 匹配行数 |
summary.matched_lines |
matched_lines |
count FILTER(dist>0 AND consumption>0) |
同上 |
| 配送总额 |
summary.total_dist_amt |
total_dist_amt |
sum(dist_amt) |
mv_distribution_monthly |
| 实际耗用 |
summary.total_consumption_amt |
total_consumption_amt |
sum(consumption_amt) |
fact_inventory_snapshot |
| 倒挤应耗用 |
summary.reverse_consumption_amt |
reverse_consumption_amt |
期初+配送-期末 |
— |
| 差异金额 |
summary.variance_amt |
variance_amt |
实际耗用-倒挤应耗用 |
— |
| 差异率 |
summary.variance_pct |
variance_pct |
差异/实际耗用×100 |
— |
倒挤公式:应耗用 = 期初 + 配送 - 期末 | 差异 = 实际 - 应耗用。
Block2:倒挤成本对账瀑布
自定义 BarChart shape 实现瀑布图:期初库存→配送入库→应耗用(倒挤)→实际耗用→期末库存→差异金额。
Block3:品类维度对账
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 品类 |
c.minor_category |
minor_category |
mv_distribution_monthly |
| 品项数 |
c.item_count |
item_count |
同上 |
| 配送量 |
c.dist_qty |
dist_qty |
同上 |
| 配送金额 |
c.dist_amt |
dist_amt |
同上 |
| 不含税成本 |
c.dist_cost_excl_tax |
dist_cost_excl_tax |
同上 |
| 耗用金额 |
c.consumption_amt |
consumption_amt |
fact_inventory_snapshot |
| 期末库存 |
c.ending_amt |
ending_amt |
同上 |
| 差异金额 |
c.variance_amt |
variance_amt |
— |
| 差异率 |
c.variance_pct |
variance_pct |
— |
分组 BarChart(配送金额/耗用金额/期末库存)+ FilterableTable。
后端使用 CTE:dist(按 minor_category 汇总配送)+ item_cat(品项分类映射)+ inv(库存按品项分类汇总),FULL OUTER JOIN。
Block4:门店差异散点图
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店名 |
s.store_name |
store_name |
mv_distribution_monthly |
| 配送金额(X) |
s.dist_amt |
dist_amt |
同上 |
| 差异率(Y) |
s.variance_pct |
variance_pct |
— |
ScatterChart,颜色按差异率分3档:正常(±3%)/关注(3~10%)/异常(>10%)。
Block5:门店对账明细
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店编码 |
s.store_code |
store_code |
mv_distribution_monthly + fact_inventory_snapshot |
| 门店名称 |
s.store_name |
store_name |
mv_distribution_monthly |
| 配送金额 |
s.dist_amt |
dist_amt |
同上 |
| 不含税成本 |
s.dist_cost_excl_tax |
dist_cost_excl_tax |
同上 |
| 期初库存 |
s.opening_amt |
opening_amt |
fact_inventory_snapshot |
| 实际耗用 |
s.consumption_amt |
consumption_amt |
同上 |
| 期末库存 |
s.ending_amt |
ending_amt |
同上 |
| 倒挤应耗用 |
s.reverse_consumption_amt |
reverse_consumption_amt |
— |
| 差异金额 |
s.variance_amt |
variance_amt |
— |
| 差异率 |
s.variance_pct |
variance_pct |
— |
| 负库存数 |
s.neg_inventory_count |
neg_inventory_count |
fact_inventory_snapshot |
后端 CTE:dist(按 store_code 汇总)+ inv(按 store_code 汇总,含 count FILTER(is_negative))+ store_names,FULL OUTER JOIN。
ORDER BY abs(差异金额) DESC。
Block6:Top30差异品项
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店 |
v.store_code |
store_code |
mv_distribution_monthly |
| 品项编码 |
v.item_code |
item_code |
同上 |
| 品项名称 |
v.item_name |
item_name |
同上 |
| 品类 |
v.minor_category |
minor_category |
同上 |
| 配送量 |
v.dist_qty |
dist_qty |
同上 |
| 配送金额 |
v.dist_amt |
dist_amt |
同上 |
| 期初 |
v.opening_amt |
opening_amt |
fact_inventory_snapshot |
| 实际耗用 |
v.consumption_amt |
consumption_amt |
同上 |
| 期末 |
v.ending_amt |
ending_amt |
同上 |
| 倒挤应耗用 |
v.reverse_consumption_amt |
reverse_consumption_amt |
— |
| 差异金额 |
v.variance_amt |
variance_amt |
— |
| 差异率 |
v.variance_pct |
variance_pct |
— |
后端 CTE:dist(按 store_code+item_code 汇总,含 item_name/unit/category)+ inv,LEFT JOIN,WHERE consumption_amt > 0,LIMIT 30。
Block7:未匹配品项(有配送无库存耗用)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 品项编码 |
u.item_code |
item_code |
mv_distribution_monthly |
| 品项名称 |
u.item_name |
item_name |
同上 |
| 品类 |
u.minor_category |
minor_category |
同上 |
| 配送量 |
u.dist_qty |
dist_qty |
同上 |
| 配送金额 |
u.dist_amt |
dist_amt |
同上 |
| 涉及门店数 |
u.store_count |
store_count |
同上 |
后端 CTE:dist_items(按 item_code 汇总,含 count(DISTINCT store_code))+ inv_items(库存中的 material_code),WHERE d.item_code NOT IN (SELECT material_code FROM inv_items),LIMIT 20。
三十、页面28:多级BOM成本穿透 BomPenetrationPage
单页面无Tab,2个API(GET overview + GET product detail),有MonthPicker。
核心数据源:central_kitchen_processing_cost、central_kitchen_recipe_consumption、analytics.fact_recipe_bom、analytics.dim_material。
API总览
| API |
触发条件 |
数据源表 |
说明 |
| /central-kitchen/bom-penetration |
页面加载 |
central_kitchen_processing_cost + recipe_consumption |
概览:产品列表+BOM汇总+多级链 |
| /central-kitchen/bom-penetration?productCode=xxx |
点击产品 |
同上 |
BOM树递归展开 |
Block1:核心指标卡片
| 显示指标 |
前端变量 |
计算公式 |
数据来源 |
| 完工产品数 |
totalProducts |
productList.length |
/central-kitchen/bom-penetration |
| 含多级BOM |
multiLevelProducts |
productList.filter(has_multi_level_bom).length |
同上 |
| BOM理论成本 |
totalBomTheoretical |
bomSummary.reduce(bom_theoretical_amt) |
同上 |
| BOM领用成本 |
totalBomIssue |
bomSummary.reduce(bom_issue_amt) |
同上 |
| 差异金额 |
totalVariance |
bomSummary.reduce(variance_amt) |
同上 |
| 半成品依赖链 |
multiLevelChains.length |
— |
同上 |
Block2:BOM成本结构Top15
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 产品编码 |
b.product_code |
product_code |
central_kitchen_processing_cost |
| 产品名称 |
b.product_name |
product_name |
同上 |
| 材料数 |
b.material_count |
material_count |
central_kitchen_recipe_consumption |
| 半成品数 |
b.sub_product_count |
sub_product_count |
同上 |
| 理论成本 |
b.bom_theoretical_amt |
bom_theoretical_amt |
同上 |
| 领用成本 |
b.bom_issue_amt |
bom_issue_amt |
同上 |
| 单位理论成本 |
b.bom_unit_theoretical_cost |
bom_unit_theoretical_cost |
— |
| 单位领用成本 |
b.bom_unit_issue_cost |
bom_unit_issue_cost |
— |
| 差异金额 |
b.variance_amt |
variance_amt |
— |
| 差异率 |
b.variance_pct |
variance_pct |
— |
分组 BarChart(理论成本+领用成本)+ FilterableTable,点击行可打开BOM树弹窗。
后端 CTE:bom(JOIN recipe_consumption + LEFT JOIN processing_cost 判断半成品),GROUP BY product_code, product_name, inbound_quantity。
Block3:BOM成本分布Treemap
Treemap,size=bom_theoretical_amt,颜色按差异率分3档。
数据来源同 Block2 的 bomSummary。
Block4:产品列表
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 产品编码 |
p.product_code |
product_code |
central_kitchen_processing_cost |
| 产品名称 |
p.product_name |
product_name |
同上 |
| 品类 |
p.category_minor |
category_minor |
同上 |
| 入库量 |
p.inbound_quantity |
inbound_quantity |
同上 |
| 理论成本 |
p.theoretical_cost |
theoretical_cost |
同上 |
| 实际成本 |
p.actual_cost |
actual_cost |
同上 |
| 材料数 |
p.material_count |
material_count |
central_kitchen_recipe_consumption |
| 多级BOM |
p.has_multi_level_bom |
has_multi_level_bom |
— |
后端 CTE:bom_materials(recipe_consumption 中的 material_code)+ finished_products(processing_cost 中的 product_code)+ multi_level(bom_materials JOIN finished_products),判断产品是否为半成品。
Block5:半成品依赖链
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 成品编码 |
c.finished_code |
finished_code |
central_kitchen_processing_cost |
| 成品名称 |
c.finished_name |
finished_name |
同上 |
| 成品配方 |
c.finished_recipe |
finished_recipe |
同上 |
| 半成品编码 |
c.sub_product_code |
sub_product_code |
central_kitchen_recipe_consumption |
| 半成品名称 |
c.sub_product_finished_name |
sub_product_finished_name |
central_kitchen_processing_cost |
| 半成品配方 |
c.sub_product_recipe |
sub_product_recipe |
同上 |
后端 CTE:bom_materials + finished_products,WHERE bm.material_code IN (SELECT product_code FROM finished_products)。
Block6:BOM树弹窗(选中产品后)
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 物料名称 |
node.material_name |
material_name |
central_kitchen_recipe_consumption |
| 编码 |
node.material_code |
material_code |
同上 |
| 单位 |
node.unit |
unit |
同上 |
| 理论量 |
node.theoretical_qty |
theoretical_qty |
同上 |
| 领用量 |
node.issue_qty |
issue_qty |
同上 |
| 理论金额 |
node.theoretical_amt |
theoretical_amt |
同上 |
| 领用金额 |
node.issue_amt |
issue_amt |
同上 |
| 差异金额 |
前端计算 |
— |
issue_amt - theoretical_amt |
后端使用 WITH RECURSIVE bom_tree 递归展开BOM,最大5层。
Level 1:直接原材料(JOIN recipe_agg ON pc.recipe_name = ra.recipe_name)。
Level 2+:递归展开半成品(WHERE bt.is_finished_product AND bt.level < 5)。
无 productCode 时 LIMIT 200,有 productCode 时按指定产品展开。
前端 buildTree() 将扁平数据构建为树结构,支持懒加载子节点。
三十一、页面29:销量驱动生产与要货计划 ProductionPlanPage
单页面无Tab,1个API(GET),有MonthPicker。
核心数据源:mv_dish_sales_monthly、analytics.fact_recipe_bom、analytics.dim_sku、analytics.dim_material、mv_distribution_monthly、analytics.fact_inventory_snapshot、central_kitchen_processing_cost、inventory_store_mapping。
API: /sales-driven/production-plan
后端使用单一连接(pool.connect()),先检查并刷新 mv_dish_sales_monthly 和 mv_distribution_monthly 物化视图,然后创建临时表 tmp_sales_agg(从物化视图导入销量数据并建索引),再 Promise.all 并发6个查询,返回 { summary, skuSales, materialDemand, storeDemand, ckProductionPlan, productionCoord }。
Block1:核心指标卡片
| 显示指标 |
前端变量 |
API字段 |
计算公式 |
数据源表 |
| 总菜品数 |
summary.total_dish_count |
total_dish_count |
count(DISTINCT dish_name) |
mv_dish_sales_monthly |
| 有BOM菜品 |
summary.matched_sku_count |
matched_sku_count |
count(*) JOIN fact_recipe_bom |
同上 + fact_recipe_bom |
| BOM覆盖率 |
summary.bom_coverage_pct |
bom_coverage_pct |
matched/total×100 |
— |
| BOM原料数 |
summary.total_bom_materials |
total_bom_materials |
count(DISTINCT material_code) |
fact_recipe_bom |
| 匹配销售额 |
summary.matched_amt |
matched_amt |
sum(amt) JOIN bom |
mv_dish_sales_monthly + fact_recipe_bom |
| 总销售额 |
summary.total_sales_amt |
total_sales_amt |
sum(amt) |
mv_dish_sales_monthly |
| CK生产计划 |
前端计算 |
— |
ckProductionPlan.filter(demand_qty>0).length |
— |
Block2:BOM覆盖率饼图 + Top15原料需求
PieChart(有BOM vs 无BOM菜品数)。
BarChart(Top15原料需求量),数据来自 materialDemand。
Block3:中央厨房生产计划
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 产品编码 |
r.product_code |
product_code |
central_kitchen_processing_cost |
| 产品名称 |
r.product_name |
product_name |
同上 |
| 需求量 |
r.demand_qty |
demand_qty |
mv_dish_sales_monthly × fact_recipe_bom |
| 实际入库 |
r.actual_inbound_qty |
actual_inbound_qty |
central_kitchen_processing_cost |
| 差异量 |
r.variance_qty |
variance_qty |
需求-实际入库 |
| 差异率 |
r.variance_pct |
variance_pct |
差异/实际入库×100 |
| 涉及门店 |
r.store_count |
store_count |
— |
| 实际成本 |
r.actual_cost |
actual_cost |
central_kitchen_processing_cost |
后端 CTE:ck_demand(销量×BOM 中 material_name IN processing_cost.product_name 的记录)+ ck_actual(processing_cost 按产品汇总),LEFT JOIN + UNION ALL(补全有实际无需求的产品)。
注意:需求与实际通过 material_name = product_name 名称匹配,非编码匹配。
Block4:生产与配送协同
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 产品编码 |
r.product_code |
product_code |
central_kitchen_processing_cost |
| 产品名称 |
r.product_name |
product_name |
同上 |
| 完工入库 |
r.inbound_qty |
inbound_qty |
同上 |
| 实际成本 |
r.actual_cost |
actual_cost |
同上 |
| 理论成本 |
r.theoretical_cost |
theoretical_cost |
同上 |
| 配送量 |
r.dist_qty |
dist_qty |
mv_distribution_monthly (DC=2) |
| 配送金额 |
r.dist_amt |
dist_amt |
同上 |
| 中央厨房出库 |
r.ck_consumption_qty |
ck_consumption_qty |
fact_inventory_snapshot (store_code='2') |
| 中央厨房期末 |
r.ck_ending_qty |
ck_ending_qty |
同上 |
| 其他仓库消耗 |
r.other_wh_consumption_qty |
other_wh_consumption_qty |
fact_inventory_snapshot (非门店非CK) |
| 其他仓库期末 |
r.other_wh_ending_qty |
other_wh_ending_qty |
同上 |
| 门店消耗 |
r.consumption_qty |
consumption_qty |
fact_inventory_snapshot (门店) |
| 门店期末库存 |
r.ending_qty |
ending_qty |
同上 |
| 完工配送率 |
r.completion_distribution_rate |
completion_distribution_rate |
配送/完工×100 |
| 配送消耗率 |
r.distribution_consumption_rate |
distribution_consumption_rate |
门店消耗/配送×100 |
| 库存积压率 |
r.inventory_accumulation_rate |
inventory_accumulation_rate |
门店期末/门店消耗×100 |
后端 CTE:ck_production + ck_distribution(DC=2) + ck_inventory(store=2) + other_wh_inventory + store_consumption,4个 FULL OUTER JOIN。
其他仓库定义:inventory_store_mapping WHERE sales_store_code IS NULL OR = '' 且 store_code != '2'。
门店定义:store_code NOT IN (非门店的 cost_unit_code)。
LIMIT 50。
Block5:门店要货建议
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 门店编码 |
r.store_code |
store_code |
mv_dish_sales_monthly |
| 门店名称 |
r.store_name |
store_name |
同上 |
| 有BOM菜品数 |
r.sku_count |
sku_count |
同上 + fact_recipe_bom |
| 销量 |
r.total_qty |
total_qty |
mv_dish_sales_monthly |
| 销售额 |
r.total_amt |
total_amt |
同上 |
| 原料需求量 |
r.total_material_demand_qty |
total_material_demand_qty |
同上 × fact_recipe_bom |
| 期末库存量 |
r.ending_inventory_qty |
ending_inventory_qty |
fact_inventory_snapshot |
| 期末库存额 |
r.ending_inventory_amt |
ending_inventory_amt |
同上 |
| 建议要货量 |
r.suggested_order_qty |
suggested_order_qty |
原料需求-期末库存 |
后端 CTE:store_demand(按 store_code 汇总销量+BOM展开)+ inv(按 store_code 汇总期末库存),LEFT JOIN。
Block6:原料需求明细
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 原料编码 |
r.material_code |
material_code |
fact_recipe_bom |
| 原料名称 |
r.material_name |
material_name |
dim_material |
| 单位 |
r.unit |
unit |
fact_recipe_bom |
| 总需求量 |
r.total_demand_qty |
total_demand_qty |
mv_dish_sales_monthly × fact_recipe_bom |
| 总需求金额 |
r.total_demand_amt |
total_demand_amt |
同上(含配送单价) |
| 涉及门店数 |
r.store_count |
store_count |
— |
| 门店均需求 |
r.avg_store_demand |
avg_store_demand |
— |
后端 CTE:demand(tmp_sales_agg JOIN fact_recipe_bom LEFT JOIN dim_material LEFT JOIN mv_distribution_monthly 获取单价),LIMIT 100。
注意:原料单价通过 m.material_name = ic.item_name 名称匹配配送记录。
Block7:SKU销量Top50
| 显示指标 |
前端变量 |
API字段 |
数据源表 |
| 菜品名称 |
r.dish_name |
dish_name |
mv_dish_sales_monthly |
| SKU编码 |
r.sku_code |
sku_code |
dim_sku |
| 销量 |
r.qty |
qty |
mv_dish_sales_monthly |
| 销售额 |
r.amt |
amt |
同上 |
| 门店数 |
r.store_count |
store_count |
同上 |
| 均价 |
r.avg_unit_price |
avg_unit_price |
同上 |
| 有BOM |
r.has_bom |
has_bom |
fact_recipe_bom |
| 材料数 |
r.material_count |
material_count |
同上 |
后端 CTE:sales(按 dish_name 汇总)LEFT JOIN dim_sku ON s.dish_name = sk.standard_name LEFT JOIN fact_recipe_bom,LIMIT 50。
注意:SKU匹配通过 dish_name = standard_name 名称匹配。