feat: 全页面增加营业收入/优惠指标 + 修复趋势预测空数据 + 区域对比口径统一 + StorePage最新经营日概览
- 后端: 所有API的discount改为从bill_fact累计discount_total - 后端: revenue/daily-summary增加consumption字段 - 后端: situational-awareness/forecast修复c175字符串比较为timestamp - 后端: region/comparison去掉未知区域排除,统一口径 - 后端: daily-card增加营业收入/优惠指标,返回target_date/baseline_date - 前端: BossPage/DashboardPage/BankPage/StorePage/ExpenseOverviewTab/RegionalPage/RegionComparisonPage/RevenuePage 均增加营业收入和优惠指标卡 - 前端: StorePage日均经营概览改为最新经营日概览,显示具体对比日期 - 前端: 日期格式统一截取YYYY-MM-DD显示
This commit is contained in:
@@ -154,7 +154,9 @@ export function BossPage() {
|
||||
|
||||
// 利润瀑布数据
|
||||
const waterfallSteps = wf ? [
|
||||
{ name: '实收', value: Number(wf.received), type: 'total' },
|
||||
{ name: '营业收入', value: Number(wf.consumption), type: 'total' },
|
||||
{ name: '优惠', value: -Number(wf.discount), type: 'cost' },
|
||||
{ name: '实收', value: Number(wf.received), type: 'subtotal' },
|
||||
{ name: '食材成本', value: -Number(wf.food_cost), type: 'cost' },
|
||||
{ name: '人工', value: -Number(wf.wage), type: 'cost' },
|
||||
{ name: '房租', value: -Number(wf.rent), type: 'cost' },
|
||||
@@ -171,6 +173,9 @@ export function BossPage() {
|
||||
if (step.type === 'total') {
|
||||
cumulative = step.value
|
||||
return { name: step.name, base: 0, value: step.value, fill: '#3b82f6' }
|
||||
} else if (step.type === 'subtotal') {
|
||||
cumulative = step.value
|
||||
return { name: step.name, base: 0, value: step.value, fill: '#6366f1' }
|
||||
} else if (step.type === 'profit') {
|
||||
return { name: step.name, base: 0, value: step.value, fill: '#22c55e' }
|
||||
} else {
|
||||
@@ -218,11 +223,13 @@ export function BossPage() {
|
||||
</div>
|
||||
|
||||
{/* ① 核心经营指标 */}
|
||||
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
|
||||
<MetricCard title="实收总额" value={ex?.total_received} format="currency" trend={trendReceived} description={`全口径${ex?.total_stores}家门店。公式:全部门店实收合计。环比上周 ${trendReceived > 0 ? '↑' : '↓'} ${Math.abs(trendReceived)}%`} />
|
||||
<MetricCard title="门店贡献利润估算" value={ex?.actual_net_profit} format="currency" status={Number(ex?.actual_net_margin_pct) < 5 ? 'bad' : Number(ex?.actual_net_margin_pct) < 10 ? 'warn' : 'good'} description={`贡献率 ${formatPercent(ex?.actual_net_margin_pct)} · 公式:实收 - 食材成本 - 经营费用(仅费用已匹配门店)。建议值:≥ 10% 优秀,5-10% 合格,< 5% 需整改`} />
|
||||
<MetricCard title="门店数" value={ex?.total_stores} unit="家" description={`盈利 ${ex?.profitable_stores}家 / 亏损 ${ex?.loss_stores}家。无费用数据 ${ex?.no_expense_stores}家`} />
|
||||
<MetricCard title="客单价" value={ex?.avg_bill_value} format="currency" trend={trend((last7.length > 0 ? sumKey(last7, 'received') / sumKey(last7, 'bill_count') : 0), (prev7.length > 0 ? sumKey(prev7, 'received') / sumKey(prev7, 'bill_count') : 0))} description={`账单 ${formatNumber(ex?.total_bills)} 笔 · 公式:实收 ÷ 账单数`} />
|
||||
<div className="grid grid-cols-2 gap-3 md:grid-cols-3 lg:grid-cols-6">
|
||||
<MetricCard title="营业收入" value={ex?.total_consumption} format="currency" description="全部门店消费金额合计" />
|
||||
<MetricCard title="优惠" value={ex?.total_discount} format="currency" description="各类优惠扣减合计" />
|
||||
<MetricCard title="实收总额" value={ex?.total_received} format="currency" trend={trendReceived} description={`全口径${ex?.total_stores}家门店。环比上周 ${trendReceived > 0 ? '↑' : '↓'} ${Math.abs(trendReceived)}%`} />
|
||||
<MetricCard title="门店贡献利润估算" value={ex?.actual_net_profit} format="currency" status={Number(ex?.actual_net_margin_pct) < 5 ? 'bad' : Number(ex?.actual_net_margin_pct) < 10 ? 'warn' : 'good'} description={`贡献率 ${formatPercent(ex?.actual_net_margin_pct)}`} />
|
||||
<MetricCard title="门店数" value={ex?.total_stores} unit="家" description={`盈利 ${ex?.profitable_stores}家 / 亏损 ${ex?.loss_stores}家`} />
|
||||
<MetricCard title="客单价" value={ex?.avg_bill_value} format="currency" trend={trend((last7.length > 0 ? sumKey(last7, 'received') / sumKey(last7, 'bill_count') : 0), (prev7.length > 0 ? sumKey(prev7, 'received') / sumKey(prev7, 'bill_count') : 0))} description={`账单 ${formatNumber(ex?.total_bills)} 笔`} />
|
||||
</div>
|
||||
|
||||
{/* ①b KPI达成率 */}
|
||||
|
||||
Reference in New Issue
Block a user