сумма] — факт за текущий месяц (реальные transactions) * @var int|null $pct_expense % бюджета по расходам за месяц (факт/план), null — если план не задан * @var object[] $goals Цели пользователя + данные счёта-копилки (account_title/account_summa/account_currency) */ use App\Classes\Currency; use System\Classes\CSRF; $type_icons = [ 'cash' => 'ic-wallet', 'bank' => 'ic-card', 'savings' => 'ic-piggy', ]; $type_accents = [ 'cash' => 'var(--teal)', 'bank' => 'var(--blue)', 'savings' => 'var(--purple)', ]; $type_labels = [ 'cash' => 'Наличные', 'bank' => 'Банковский счёт', 'savings' => 'Копилка', ]; $weekdays = [1 => 'Понедельник', 2 => 'Вторник', 3 => 'Среда', 4 => 'Четверг', 5 => 'Пятница', 6 => 'Суббота', 7 => 'Воскресенье']; $month_names = [ 1 => 'январь', 2 => 'февраль', 3 => 'март', 4 => 'апрель', 5 => 'май', 6 => 'июнь', 7 => 'июль', 8 => 'август', 9 => 'сентябрь', 10 => 'октябрь', 11 => 'ноябрь', 12 => 'декабрь', ]; $month_names_gen = [ 1 => 'января', 2 => 'февраля', 3 => 'марта', 4 => 'апреля', 5 => 'мая', 6 => 'июня', 7 => 'июля', 8 => 'августа', 9 => 'сентября', 10 => 'октября', 11 => 'ноября', 12 => 'декабря', ]; $ucfirstMb = static fn (string $s): string => mb_strtoupper(mb_substr($s, 0, 1)) . mb_substr($s, 1); $this->setScript('accounts.js'); ?>
,
📅 100; ?> Бюджет % потрачено
Здравствуйте,
Доступно сейчас
₽
Всего по всем счетам ₽
Счета
Пока нет ни одного счёта — нажмите «+», чтобы добавить первый
title, ENT_QUOTES, 'UTF-8') ?>
type_acc] ?? '' ?>
summa, 2, ',', ' ') ?> currency, ENT_QUOTES, 'UTF-8') ?>
Копилки и цели
account_summa; $target = (float)$goal->target_summa; $pct = $target > 0 ? min(100, $saved / $target * 100) : 0; $r = 22; $circumference = 2 * M_PI * $r; $offset = $circumference * (1 - $pct / 100); ?>
%
account_title, ENT_QUOTES, 'UTF-8') ?>
из account_currency, ENT_QUOTES, 'UTF-8') ?>
$g->type === $type); if ($type_groups === []) { echo '
Нет статей — добавьте их на странице «Статьи»
'; return; } // Строка одной статьи (или самостоятельной группы без детей) — план+факт+прогресс-бар. // Перерасход (факт > плана) для расходов подсвечивается красным — для доходов это, наоборот, // хорошо (получено больше плана), там всегда акцентный цвет. $renderRow = static function (object $category, float $plan, float $fact, string $type): void { $pct = $plan > 0 ? round($fact / $plan * 100) : ($fact > 0 ? 100 : 0); $bar_width = min(100, $pct); $over = $type === 'expense' && $fact > $plan && $plan > 0; $pct_color = $over ? 'var(--red)' : 'var(--accent-tint)'; $bar_color = $over ? 'var(--red)' : 'var(--accent)'; echo '
' . '
' . '
' . htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') . '
' . '
' . '
' . number_format($fact, 0, ',', ' ') . ' из ' . number_format($plan, 0, ',', ' ') . ' ₽
' . '
' . '
' . $pct . '%
' . '
'; }; echo '
'; foreach ($type_groups as $group) { $children = $tree[$group->id] ?? []; // Заголовок-плашка — ВСЕГДА, и у настоящей группы, и у самостоятельной статьи (тогда // плашка — единственная строка на неё, показывает сразу и название, и сумму). Без этого // самостоятельная статья визуально не отличалась от рядового члена предыдущей группы // (см. фидбек пользователя — тонкой разницы фона недостаточно, нужна однозначная граница). $head_plan = $children !== [] ? array_sum(array_map(static fn ($c) => $plan_month[$c->id] ?? 0.0, $children)) : ($plan_month[$group->id] ?? 0.0); echo '
' . '' . htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') . '' . '' . number_format($head_plan, 0, ',', ' ') . ' ₽' . '
'; // Самостоятельная статья (без подкатегорий) — плашка выше уже единственная строка на неё // (название+план), отдельного .budget-row для неё не рисуем (см. комментарий выше). foreach ($children as $category) { $renderRow($category, $plan_month[$category->id] ?? 0.0, $fact_month[$category->id] ?? 0.0, $type); } } echo '
'; }; ?>
Доходы
Бюджет на