feat: 利润与成本指标卡增加颜色标识 - 绿色正常/黄色关注/红色问题
This commit is contained in:
@@ -8,9 +8,22 @@ interface MetricCardProps {
|
|||||||
trend?: number
|
trend?: number
|
||||||
description?: string
|
description?: string
|
||||||
className?: 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'
|
const displayValue = format === 'percent'
|
||||||
? value === null || value === undefined ? '-' : `${Number(value).toFixed(2)}%`
|
? value === null || value === undefined ? '-' : `${Number(value).toFixed(2)}%`
|
||||||
: format === 'currency'
|
: format === 'currency'
|
||||||
@@ -20,7 +33,7 @@ export function MetricCard({ title, value, unit, format = 'number', trend, descr
|
|||||||
: formatNumber(value)
|
: formatNumber(value)
|
||||||
|
|
||||||
return (
|
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">
|
<div className="flex items-center gap-1">
|
||||||
<p className="text-sm text-muted-foreground">{title}</p>
|
<p className="text-sm text-muted-foreground">{title}</p>
|
||||||
{description && (
|
{description && (
|
||||||
@@ -33,7 +46,7 @@ export function MetricCard({ title, value, unit, format = 'number', trend, descr
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-baseline gap-1">
|
<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>}
|
{unit && <span className="text-sm text-muted-foreground">{unit}</span>}
|
||||||
</div>
|
</div>
|
||||||
{trend !== undefined && (
|
{trend !== undefined && (
|
||||||
|
|||||||
@@ -192,16 +192,16 @@ export function DashboardPage() {
|
|||||||
{ex && (
|
{ex && (
|
||||||
<CollapsibleSection title="利润与成本" subtitle="食材成本、经营费用、净利润等财务指标">
|
<CollapsibleSection title="利润与成本" subtitle="食材成本、经营费用、净利润等财务指标">
|
||||||
<div className="grid grid-cols-2 gap-3 md:grid-cols-4">
|
<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.theoretical_net_profit} format="currency" status="good" 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.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" description={`成本率 ${formatPercent(ex.actual_food_cost_rate_pct)} · 理论成本率 ${formatPercent(ex.theoretical_food_cost_rate_pct)}`} />
|
<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" description={`费用率 ${formatPercent(ex.overall_expense_rate_pct)} · 人工 ${formatCurrency(ex.total_wage)} · 房租 ${formatCurrency(ex.total_rent)}`} />
|
<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>
|
||||||
<div className="mt-3 grid grid-cols-2 gap-3 md:grid-cols-4">
|
<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_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" description={`占实收 ${formatPercent(ex.overall_rent_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" description={`占实收 ${formatPercent(ex.overall_utility_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" description="外卖平台佣金合计" />
|
<MetricCard title="外卖佣金" value={ex.total_commission} format="currency" status={Number(ex.total_commission) > 4000000 ? 'warn' : 'good'} description="外卖平台佣金合计" />
|
||||||
</div>
|
</div>
|
||||||
</CollapsibleSection>
|
</CollapsibleSection>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user