feat: 利润与成本指标卡增加颜色标识 - 绿色正常/黄色关注/红色问题
This commit is contained in:
@@ -8,9 +8,22 @@ interface MetricCardProps {
|
||||
trend?: number
|
||||
description?: string
|
||||
className?: string
|
||||
status?: 'good' | 'warn' | 'bad'
|
||||
}
|
||||
|
||||
export function MetricCard({ title, value, unit, format = 'number', trend, description, className }: MetricCardProps) {
|
||||
const STATUS_STYLES: Record<string, string> = {
|
||||
good: 'border-green-200 bg-green-50/40',
|
||||
warn: 'border-yellow-200 bg-yellow-50/40',
|
||||
bad: 'border-red-200 bg-red-50/40',
|
||||
}
|
||||
|
||||
const STATUS_VALUE_STYLES: Record<string, string> = {
|
||||
good: 'text-green-700',
|
||||
warn: 'text-yellow-700',
|
||||
bad: 'text-red-700',
|
||||
}
|
||||
|
||||
export function MetricCard({ title, value, unit, format = 'number', trend, description, className, status }: MetricCardProps) {
|
||||
const displayValue = format === 'percent'
|
||||
? value === null || value === undefined ? '-' : `${Number(value).toFixed(2)}%`
|
||||
: format === 'currency'
|
||||
@@ -20,7 +33,7 @@ export function MetricCard({ title, value, unit, format = 'number', trend, descr
|
||||
: formatNumber(value)
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-lg border bg-card p-4 shadow-sm', className)}>
|
||||
<div className={cn('rounded-lg border bg-card p-4 shadow-sm', status && STATUS_STYLES[status], className)}>
|
||||
<div className="flex items-center gap-1">
|
||||
<p className="text-sm text-muted-foreground">{title}</p>
|
||||
{description && (
|
||||
@@ -33,7 +46,7 @@ export function MetricCard({ title, value, unit, format = 'number', trend, descr
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-2 flex items-baseline gap-1">
|
||||
<span className="text-2xl font-bold">{displayValue}</span>
|
||||
<span className={cn('text-2xl font-bold', status && STATUS_VALUE_STYLES[status])}>{displayValue}</span>
|
||||
{unit && <span className="text-sm text-muted-foreground">{unit}</span>}
|
||||
</div>
|
||||
{trend !== undefined && (
|
||||
|
||||
@@ -192,16 +192,16 @@ export function DashboardPage() {
|
||||
{ex && (
|
||||
<CollapsibleSection title="利润与成本" subtitle="食材成本、经营费用、净利润等财务指标">
|
||||
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
|
||||
<MetricCard title="理论净利润" value={ex.theoretical_net_profit} format="currency" description={`净利率 ${formatPercent(ex.theoretical_net_margin_pct)} · 按标准成本计算的理论利润`} />
|
||||
<MetricCard title="实际净利润" value={ex.actual_net_profit} format="currency" description={`净利率 ${formatPercent(ex.actual_net_margin_pct)} · 盈利 ${ex.profitable_stores}家 / 亏损 ${ex.loss_stores}家`} />
|
||||
<MetricCard title="食材成本" value={ex.total_food_cost} format="currency" description={`成本率 ${formatPercent(ex.actual_food_cost_rate_pct)} · 理论成本率 ${formatPercent(ex.theoretical_food_cost_rate_pct)}`} />
|
||||
<MetricCard title="经营费用" value={ex.total_expense} format="currency" description={`费用率 ${formatPercent(ex.overall_expense_rate_pct)} · 人工 ${formatCurrency(ex.total_wage)} · 房租 ${formatCurrency(ex.total_rent)}`} />
|
||||
<MetricCard title="理论净利润" value={ex.theoretical_net_profit} format="currency" status="good" description={`净利率 ${formatPercent(ex.theoretical_net_margin_pct)} · 按标准成本计算的理论利润`} />
|
||||
<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)} · 盈利 ${ex.profitable_stores}家 / 亏损 ${ex.loss_stores}家`} />
|
||||
<MetricCard title="食材成本" value={ex.total_food_cost} format="currency" status={Number(ex.actual_food_cost_rate_pct) - Number(ex.theoretical_food_cost_rate_pct) > 10 ? 'bad' : Number(ex.actual_food_cost_rate_pct) - Number(ex.theoretical_food_cost_rate_pct) > 5 ? 'warn' : 'good'} description={`成本率 ${formatPercent(ex.actual_food_cost_rate_pct)} · 理论成本率 ${formatPercent(ex.theoretical_food_cost_rate_pct)} · 差异 ${formatPercent(Number(ex.actual_food_cost_rate_pct) - Number(ex.theoretical_food_cost_rate_pct))}`} />
|
||||
<MetricCard title="经营费用" value={ex.total_expense} format="currency" status={Number(ex.overall_expense_rate_pct) > 50 ? 'bad' : Number(ex.overall_expense_rate_pct) > 40 ? 'warn' : 'good'} description={`费用率 ${formatPercent(ex.overall_expense_rate_pct)} · 人工 ${formatCurrency(ex.total_wage)} · 房租 ${formatCurrency(ex.total_rent)}`} />
|
||||
</div>
|
||||
<div className="mt-3 grid grid-cols-2 gap-3 md:grid-cols-4">
|
||||
<MetricCard title="人工费用" value={ex.total_wage} format="currency" description={`占实收 ${formatPercent(ex.overall_wage_rate_pct)}`} />
|
||||
<MetricCard title="房租费用" value={ex.total_rent} format="currency" description={`占实收 ${formatPercent(ex.overall_rent_rate_pct)}`} />
|
||||
<MetricCard title="水电费用" value={ex.total_utility} format="currency" description={`占实收 ${formatPercent(ex.overall_utility_rate_pct)}`} />
|
||||
<MetricCard title="外卖佣金" value={ex.total_commission} format="currency" description="外卖平台佣金合计" />
|
||||
<MetricCard title="人工费用" value={ex.total_wage} format="currency" status={Number(ex.overall_wage_rate_pct) > 30 ? 'bad' : Number(ex.overall_wage_rate_pct) > 25 ? 'warn' : 'good'} description={`占实收 ${formatPercent(ex.overall_wage_rate_pct)}`} />
|
||||
<MetricCard title="房租费用" value={ex.total_rent} format="currency" status={Number(ex.overall_rent_rate_pct) > 20 ? 'bad' : Number(ex.overall_rent_rate_pct) > 15 ? 'warn' : 'good'} description={`占实收 ${formatPercent(ex.overall_rent_rate_pct)}`} />
|
||||
<MetricCard title="水电费用" value={ex.total_utility} format="currency" status={Number(ex.overall_utility_rate_pct) > 8 ? 'warn' : 'good'} description={`占实收 ${formatPercent(ex.overall_utility_rate_pct)}`} />
|
||||
<MetricCard title="外卖佣金" value={ex.total_commission} format="currency" status={Number(ex.total_commission) > 4000000 ? 'warn' : 'good'} description="外卖平台佣金合计" />
|
||||
</div>
|
||||
</CollapsibleSection>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user