62 lines
4.1 KiB
TypeScript
62 lines
4.1 KiB
TypeScript
|
|
|
|||
|
|
import React from 'react';
|
|||
|
|
import { TrendingUp, TrendingDown, Activity, ArrowUpRight } from 'lucide-react';
|
|||
|
|
|
|||
|
|
const FinancialKPI: React.FC<{ title: string; value: string; trend?: 'up' | 'down'; subtext?: string }> = ({ title, value, trend, subtext }) => {
|
|||
|
|
const TrendIcon = trend === 'up' ? TrendingUp : trend === 'down' ? TrendingDown : null;
|
|||
|
|
const trendColor = trend === 'up' ? 'text-emerald-500' : trend === 'down' ? 'text-red-500' : 'text-slate-400';
|
|||
|
|
return (
|
|||
|
|
<div className="bg-white p-4 rounded-xl border border-slate-200 shadow-sm">
|
|||
|
|
<p className="text-xs text-slate-500 font-bold uppercase">{title}</p>
|
|||
|
|
<div className="flex justify-between items-end mt-2">
|
|||
|
|
<div>
|
|||
|
|
<p className="text-2xl font-black text-slate-800">{value}</p>
|
|||
|
|
{subtext && <p className="text-[10px] text-slate-400 font-medium mt-1">{subtext}</p>}
|
|||
|
|
</div>
|
|||
|
|
{TrendIcon && <TrendIcon className={`w-5 h-5 ${trendColor}`} />}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
export const FinanceSummary: React.FC<{ data: any }> = ({ data }) => {
|
|||
|
|
return (
|
|||
|
|
<div className="space-y-6 animate-fade-in">
|
|||
|
|
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|||
|
|
<FinancialKPI title="Общий баланс" value={`${(data.totalBalance / 1_000_000).toFixed(1)}M ₽`} subtext="Свободные средства" />
|
|||
|
|
<FinancialKPI title="В графике" value={`${(data.scheduledAmount / 1000).toFixed(0)}k ₽`} trend="up" subtext="К оплате до конца нед." />
|
|||
|
|
<FinancialKPI title="Дебиторка" value={`${(data.totalDebt / 1_000_000).toFixed(1)}M ₽`} trend="down" />
|
|||
|
|
<FinancialKPI title="Закрывающие" value={data.missingDocs.toString()} subtext="Счетов без актов" />
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|||
|
|
<div className="lg:col-span-2 bg-white p-6 rounded-2xl border border-slate-200 shadow-sm">
|
|||
|
|
<h3 className="font-bold text-slate-800 mb-4">Финансовый прогноз (Кассовый план)</h3>
|
|||
|
|
<div className="h-48 flex items-end justify-between gap-2">
|
|||
|
|
{[4.2, 5.1, 3.8, 4.9, 6.2, 4.5].map((val, i) => (
|
|||
|
|
<div key={i} className="flex-1 flex flex-col items-center gap-2">
|
|||
|
|
<div className="w-full bg-slate-100 rounded-t-lg relative overflow-hidden h-32">
|
|||
|
|
<div className="absolute bottom-0 w-full bg-indigo-500/20" style={{ height: `${val * 15}%` }} />
|
|||
|
|
<div className="absolute bottom-0 w-full bg-indigo-500 rounded-t h-2" style={{ bottom: `${val * 15}%` }} />
|
|||
|
|
</div>
|
|||
|
|
<span className="text-[10px] font-bold text-slate-400">Нед.{i+1}</span>
|
|||
|
|
</div>
|
|||
|
|
))}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div className="bg-gradient-to-br from-indigo-600 to-indigo-800 p-5 rounded-2xl text-white shadow-xl relative overflow-hidden">
|
|||
|
|
<ArrowUpRight className="absolute -top-4 -right-4 w-24 h-24 text-white opacity-10" />
|
|||
|
|
<h4 className="font-bold text-sm mb-2">Совет казначея</h4>
|
|||
|
|
<p className="text-[11px] text-indigo-100 leading-relaxed mb-4">
|
|||
|
|
У вас {data.missingDocs} оплаченных счетов без закрывающих актов. Это создает риски при налоговой проверке. Рекомендуем запросить документы у подрядчиков перед следующей выплатой.
|
|||
|
|
</p>
|
|||
|
|
<button className="w-full py-2 bg-white/20 hover:bg-white/30 rounded-lg text-[10px] font-black uppercase transition-colors">
|
|||
|
|
Сформировать реестр
|
|||
|
|
</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
);
|
|||
|
|
};
|