497 lines
31 KiB
HTML
497 lines
31 KiB
HTML
<?php
|
||
/**
|
||
* @package Bicycle
|
||
* @description budgets.html — план бюджета на год по месяцам. Своя раскладка на каждое
|
||
* устройство (см. .claude/memory/бюджет_текущий_план.md → обсуждение дизайна):
|
||
* комп/планшет — карточки статьи с 12 месяцами (планшет — сеткой 6×2 вместо
|
||
* ряда, через container query); телефон — раскрывающиеся карточки-аккордeоны
|
||
* (все 12 месяцев по тапу). Ни один режим не даёт горизонтальный скролл.
|
||
* Факт (реальные transactions) здесь не показывается.
|
||
*
|
||
* @var array<int,object[]> $tree Активные статьи пользователя, сгруппированные по group_id (0 — без группы)
|
||
* @var object[] $groups Активные группы пользователя (App\Repositories\CategoryGroupRepository)
|
||
* @var array $plan [categorie_id => [month => ['plan_summ'=>float,'formula_pct_used'=>?float]]]
|
||
* @var int $year
|
||
* @var object[] $archived Архивные статьи пользователя — для модалки «Статьи» → архив
|
||
* @var object[] $archived_groups Архивные группы пользователя — туда же
|
||
*/
|
||
|
||
use System\Classes\CSRF;
|
||
|
||
$months = [
|
||
1 => 'Янв', 2 => 'Фев', 3 => 'Мар', 4 => 'Апр', 5 => 'Май', 6 => 'Июн',
|
||
7 => 'Июл', 8 => 'Авг', 9 => 'Сен', 10 => 'Окт', 11 => 'Ноя', 12 => 'Дек',
|
||
];
|
||
|
||
$sections = [
|
||
'income' => 'Доходы',
|
||
'expense' => 'Расходы',
|
||
];
|
||
|
||
// Плоский список активных статей (группа — отдельная сущность, сюда не входит) — для select'а
|
||
// формулы в модалке «Статьи» (только статьи расхода могут быть целью формулы, не группы).
|
||
$all = [];
|
||
foreach ($tree as $items) {
|
||
$all = array_merge($all, $items);
|
||
}
|
||
|
||
// Категории, чей план считается автоматически по формуле связанной income-статьи —
|
||
// у них своя ячейка readonly (см. CategoriesController::parseFormulaLink()).
|
||
$formula_targets = [];
|
||
foreach ($tree as $items) {
|
||
foreach ($items as $c) {
|
||
if ($c->linked_expense_categorie_id) {
|
||
$formula_targets[(int)$c->linked_expense_categorie_id] = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Одна ячейка ввода — общая и для карточек (комп/планшет), и для аккордeона (телефон),
|
||
* чтобы имя поля/значение/readonly не разъезжались между двумя разметками одних данных.
|
||
*/
|
||
$planInput = static function (int $categorie_id, int $month, array $plan, bool $readonly) {
|
||
$value = $plan[$categorie_id][$month]['plan_summ'] ?? '';
|
||
echo '<input type="number" step="0.01" min="0" class="plan-input num" name="plan[' . $categorie_id . '][' . $month . ']"'
|
||
. ' value="' . htmlspecialchars((string)$value, ENT_QUOTES, 'UTF-8') . '"' . ($readonly ? ' readonly' : '') . '>';
|
||
};
|
||
|
||
$this->setScript('budgets.js');
|
||
$this->setScript('categories.js');
|
||
?>
|
||
|
||
<svg width="0" height="0" style="position:absolute">
|
||
<defs>
|
||
<symbol id="ic-plus" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<line x1="12" y1="5" x2="12" y2="19"/>
|
||
<line x1="5" y1="12" x2="19" y2="12"/>
|
||
</symbol>
|
||
<symbol id="ic-dots" viewBox="0 0 24 24" fill="currentColor">
|
||
<circle cx="12" cy="5" r="1.6"/>
|
||
<circle cx="12" cy="12" r="1.6"/>
|
||
<circle cx="12" cy="19" r="1.6"/>
|
||
</symbol>
|
||
<symbol id="ic-pencil" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M12 20h9"/>
|
||
<path d="M16.5 3.5a2.12 2.12 0 0 1 3 3L7 19l-4 1 1-4Z"/>
|
||
</symbol>
|
||
<symbol id="ic-trash" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 6h18"/>
|
||
<path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>
|
||
<path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/>
|
||
</symbol>
|
||
<symbol id="ic-archive" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="2" y="4" width="20" height="5" rx="1"/>
|
||
<path d="M4 9v9a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9"/>
|
||
<line x1="10" y1="13" x2="14" y2="13"/>
|
||
</symbol>
|
||
<symbol id="ic-undo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 10h10a5 5 0 0 1 0 10H8"/>
|
||
<path d="M8 5 3 10l5 5"/>
|
||
</symbol>
|
||
<symbol id="ic-folder" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/>
|
||
</symbol>
|
||
<symbol id="ic-folder-plus" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/>
|
||
<line x1="12" y1="10" x2="12" y2="15"/>
|
||
<line x1="9.5" y1="12.5" x2="14.5" y2="12.5"/>
|
||
</symbol>
|
||
</defs>
|
||
</svg>
|
||
|
||
<div class="top-row">
|
||
<div>
|
||
<div class="hello">План бюджета на год</div>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:0.75rem;">
|
||
<a class="btn btn-outline-light btn-sm" href="?year=<?= $year - 1 ?>">←</a>
|
||
<div class="balance num" style="font-size:2rem;"><?= $year ?></div>
|
||
<a class="btn btn-outline-light btn-sm" href="?year=<?= $year + 1 ?>">→</a>
|
||
<button type="button" class="btn btn-primary js-categories-open" style="display:inline-flex;align-items:center;gap:6px">
|
||
<svg class="ico" style="width:0.95em;height:0.95em"><use href="#ic-gear"/></svg>
|
||
Статьи
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<form id="budgets-form" method="post" action="/budgets/save">
|
||
<?= CSRF::field() ?>
|
||
<input type="hidden" name="year" value="<?= $year ?>">
|
||
|
||
<?php foreach ($sections as $type => $label): ?>
|
||
<div class="section-label"><span><?= $label ?></span></div>
|
||
|
||
<?php
|
||
$type_groups = array_filter($groups, static fn ($g) => $g->type === $type);
|
||
$ungrouped = array_filter($tree[0] ?? [], static fn ($c) => $c->type === $type);
|
||
?>
|
||
|
||
<?php if (empty($type_groups) && empty($ungrouped)): ?>
|
||
<div class="empty-state">Нет статей — сначала добавьте их на странице «Статьи»</div>
|
||
<?php else: ?>
|
||
<div class="budget-zoom">
|
||
|
||
<!-- ---------- комп/планшет: карточки, 12 месяцев (планшет — сеткой 6×2) ---------- -->
|
||
<div class="budget-cards-wrap">
|
||
<?php foreach ($type_groups as $group): ?>
|
||
<?php $children = $tree[$group->id] ?? []; ?>
|
||
<div class="budget-plan-group">
|
||
<div class="budget-group-head" style="--card-accent:var(--blue)">
|
||
<span class="budget-group-name"><?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
</div>
|
||
<div class="budget-cards">
|
||
<?php foreach ($children as $category): ?>
|
||
<?php $is_target = isset($formula_targets[(int)$category->id]); ?>
|
||
<div class="budget-card">
|
||
<div class="budget-card-name"><?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="budget-months-inline">
|
||
<?php foreach ($months as $m => $mlabel): ?>
|
||
<div class="budget-cell">
|
||
<div class="budget-cell-label"><?= $mlabel ?></div>
|
||
<?php $planInput((int)$category->id, $m, $plan, $is_target); ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
|
||
<?php foreach ($ungrouped as $category): ?>
|
||
<?php $is_target = isset($formula_targets[(int)$category->id]); ?>
|
||
<div class="budget-plan-group">
|
||
<div class="budget-cards">
|
||
<div class="budget-card">
|
||
<div class="budget-card-name"><?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="budget-months-inline">
|
||
<?php foreach ($months as $m => $mlabel): ?>
|
||
<div class="budget-cell">
|
||
<div class="budget-cell-label"><?= $mlabel ?></div>
|
||
<?php $planInput((int)$category->id, $m, $plan, $is_target); ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<!-- ---------- телефон: один аккордeон на группу или самостоятельную статью ---------- -->
|
||
<div class="budget-accordion">
|
||
<?php foreach ($type_groups as $group): ?>
|
||
<?php
|
||
$children = $tree[$group->id] ?? [];
|
||
$year_sum = 0.0;
|
||
foreach ($children as $row_category) {
|
||
foreach ($months as $m => $_) {
|
||
$year_sum += (float)($plan[$row_category->id][$m]['plan_summ'] ?? 0);
|
||
}
|
||
}
|
||
?>
|
||
<details class="budget-acc-card">
|
||
<summary>
|
||
<span class="budget-acc-name"><?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
<span class="budget-acc-total num"><?= number_format($year_sum, 0, ',', ' ') ?> ₽/год</span>
|
||
</summary>
|
||
<?php foreach ($children as $category): ?>
|
||
<?php $is_target = isset($formula_targets[(int)$category->id]); ?>
|
||
<div class="budget-acc-caption"><?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="budget-acc-body">
|
||
<?php foreach ($months as $m => $mlabel): ?>
|
||
<div class="budget-acc-month">
|
||
<span><?= $mlabel ?></span>
|
||
<?php $planInput((int)$category->id, $m, $plan, $is_target); ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</details>
|
||
<?php endforeach; ?>
|
||
|
||
<?php foreach ($ungrouped as $category): ?>
|
||
<?php
|
||
$is_target = isset($formula_targets[(int)$category->id]);
|
||
$year_sum = 0.0;
|
||
foreach ($months as $m => $_) {
|
||
$year_sum += (float)($plan[$category->id][$m]['plan_summ'] ?? 0);
|
||
}
|
||
?>
|
||
<details class="budget-acc-card">
|
||
<summary>
|
||
<span class="budget-acc-name"><?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
<span class="budget-acc-total num"><?= number_format($year_sum, 0, ',', ' ') ?> ₽/год</span>
|
||
</summary>
|
||
<div class="budget-acc-body">
|
||
<?php foreach ($months as $m => $mlabel): ?>
|
||
<div class="budget-acc-month">
|
||
<span><?= $mlabel ?></span>
|
||
<?php $planInput((int)$category->id, $m, $plan, $is_target); ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</details>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php endforeach; ?>
|
||
|
||
<div id="budgets-form-error" class="alert alert-danger" style="display:none"></div>
|
||
</form>
|
||
|
||
<div class="modal fade" id="categories-modal" tabindex="-1" data-bs-theme="dark">
|
||
<div class="modal-dialog modal-dialog-scrollable" style="max-width:640px">
|
||
<div class="modal-content" style="background:var(--surface);color:var(--ink);border-radius:var(--radius-lg)">
|
||
<div class="modal-header" style="border-color:var(--surface-3)">
|
||
<h5 class="modal-title">Статьи доходов и расходов</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||
</div>
|
||
|
||
<div class="modal-body" style="padding:0">
|
||
<?php foreach ($sections as $type => $label): ?>
|
||
<div class="section-label">
|
||
<span><?= $label ?></span>
|
||
<div style="display:flex;gap:0.5rem;">
|
||
<button type="button" class="btn-add js-category-archive-open" title="Архив"><svg class="ico"><use href="#ic-archive"/></svg></button>
|
||
<button type="button" class="btn-add js-group-add" data-type="<?= $type ?>" title="Добавить группу"><svg class="ico"><use href="#ic-folder-plus"/></svg></button>
|
||
<button type="button" class="btn-add js-category-add" data-type="<?= $type ?>" title="Добавить статью"><svg class="ico"><use href="#ic-plus"/></svg></button>
|
||
</div>
|
||
</div>
|
||
|
||
<?php
|
||
$type_groups = array_filter($groups, static fn ($g) => $g->type === $type);
|
||
$ungrouped = array_filter($tree[0] ?? [], static fn ($c) => $c->type === $type);
|
||
?>
|
||
|
||
<?php if (empty($type_groups) && empty($ungrouped)): ?>
|
||
<div class="empty-state">Пока нет ни одной статьи — нажмите «+», чтобы добавить первую</div>
|
||
<?php else: ?>
|
||
<div class="category-list">
|
||
<?php foreach ($type_groups as $group): ?>
|
||
<div class="category-row category-group"
|
||
data-id="<?= (int)$group->id ?>"
|
||
data-title="<?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?>"
|
||
data-type="<?= $group->type ?>">
|
||
<div class="category-row-main">
|
||
<svg class="ico"><use href="#ic-folder"/></svg>
|
||
<span class="room-title"><?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
</div>
|
||
<div class="room-menu">
|
||
<button type="button" class="room-menu-btn"><svg class="ico"><use href="#ic-dots"/></svg></button>
|
||
<div class="room-menu-list">
|
||
<a href="#" class="js-group-edit"><svg class="ico ico-sm"><use href="#ic-pencil"/></svg>Редактировать</a>
|
||
<a href="#" class="danger js-group-delete"><svg class="ico ico-sm"><use href="#ic-trash"/></svg>Архивировать</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php foreach ($tree[$group->id] ?? [] as $sub): ?>
|
||
<div class="category-row category-sub"
|
||
data-id="<?= (int)$sub->id ?>"
|
||
data-title="<?= htmlspecialchars($sub->title, ENT_QUOTES, 'UTF-8') ?>"
|
||
data-type="<?= $sub->type ?>"
|
||
data-group_id="<?= (int)$sub->group_id ?>"
|
||
data-linked="<?= (int)($sub->linked_expense_categorie_id ?? 0) ?>"
|
||
data-pct="<?= htmlspecialchars((string)($sub->formula_pct ?? ''), ENT_QUOTES, 'UTF-8') ?>">
|
||
<div class="category-row-main">
|
||
<span class="room-title"><?= htmlspecialchars($sub->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
<?php if ($sub->linked_expense_categorie_id): ?>
|
||
<span class="room-sub">→ формула <?= htmlspecialchars((string)$sub->formula_pct, ENT_QUOTES, 'UTF-8') ?>%</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="room-menu">
|
||
<button type="button" class="room-menu-btn"><svg class="ico"><use href="#ic-dots"/></svg></button>
|
||
<div class="room-menu-list">
|
||
<a href="#" class="js-category-edit"><svg class="ico ico-sm"><use href="#ic-pencil"/></svg>Редактировать</a>
|
||
<label class="room-menu-move">
|
||
<svg class="ico ico-sm"><use href="#ic-folder"/></svg>
|
||
<select class="js-category-move">
|
||
<option value="">Перенести в...</option>
|
||
<?php foreach ($groups as $move_group): ?>
|
||
<?php if ($move_group->type === $sub->type && $move_group->id !== $sub->group_id): ?>
|
||
<option value="<?= (int)$move_group->id ?>"><?= htmlspecialchars($move_group->title, ENT_QUOTES, 'UTF-8') ?></option>
|
||
<?php endif; ?>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
<a href="#" class="danger js-category-delete"><svg class="ico ico-sm"><use href="#ic-trash"/></svg>Архивировать</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php endforeach; ?>
|
||
|
||
<?php foreach ($ungrouped as $sub): ?>
|
||
<div class="category-row"
|
||
data-id="<?= (int)$sub->id ?>"
|
||
data-title="<?= htmlspecialchars($sub->title, ENT_QUOTES, 'UTF-8') ?>"
|
||
data-type="<?= $sub->type ?>"
|
||
data-group_id=""
|
||
data-linked="<?= (int)($sub->linked_expense_categorie_id ?? 0) ?>"
|
||
data-pct="<?= htmlspecialchars((string)($sub->formula_pct ?? ''), ENT_QUOTES, 'UTF-8') ?>">
|
||
<div class="category-row-main">
|
||
<span class="room-title"><?= htmlspecialchars($sub->title, ENT_QUOTES, 'UTF-8') ?></span>
|
||
<?php if ($sub->linked_expense_categorie_id): ?>
|
||
<span class="room-sub">→ формула <?= htmlspecialchars((string)$sub->formula_pct, ENT_QUOTES, 'UTF-8') ?>%</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="room-menu">
|
||
<button type="button" class="room-menu-btn"><svg class="ico"><use href="#ic-dots"/></svg></button>
|
||
<div class="room-menu-list">
|
||
<a href="#" class="js-category-edit"><svg class="ico ico-sm"><use href="#ic-pencil"/></svg>Редактировать</a>
|
||
<?php if (!empty($groups)): ?>
|
||
<label class="room-menu-move">
|
||
<svg class="ico ico-sm"><use href="#ic-folder"/></svg>
|
||
<select class="js-category-move">
|
||
<option value="">Перенести в...</option>
|
||
<?php foreach ($groups as $move_group): ?>
|
||
<?php if ($move_group->type === $sub->type): ?>
|
||
<option value="<?= (int)$move_group->id ?>"><?= htmlspecialchars($move_group->title, ENT_QUOTES, 'UTF-8') ?></option>
|
||
<?php endif; ?>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</label>
|
||
<?php endif; ?>
|
||
<a href="#" class="danger js-category-delete"><svg class="ico ico-sm"><use href="#ic-trash"/></svg>Архивировать</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal fade" id="category-modal" tabindex="-1" data-bs-theme="dark">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content" style="background:var(--surface-2);color:var(--ink);">
|
||
<form id="category-form" method="post">
|
||
<?= CSRF::field() ?>
|
||
<input type="hidden" name="id">
|
||
<input type="hidden" name="type" id="category-type">
|
||
<div class="modal-header" style="border-color:var(--surface-3)">
|
||
<h5 class="modal-title" id="category-modal-title">Новая статья</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div id="category-form-error" class="alert alert-danger" style="display:none"></div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Название</label>
|
||
<input type="text" class="form-control" name="title" maxlength="128" required>
|
||
</div>
|
||
|
||
<div class="mb-3">
|
||
<label class="form-label">Группа</label>
|
||
<select class="form-select" name="group_id" id="category-group">
|
||
<option value="">— без группы —</option>
|
||
<?php foreach ($groups as $group): ?>
|
||
<option value="<?= (int)$group->id ?>" data-type="<?= $group->type ?>"><?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
|
||
<div class="mb-3" id="category-formula-group" style="display:none">
|
||
<label class="form-label">Формула — связанная статья расхода</label>
|
||
<select class="form-select mb-2" name="linked_expense_categorie_id" id="category-linked">
|
||
<option value="">— не привязано —</option>
|
||
<?php foreach ($all as $c): ?>
|
||
<?php if ($c->type === 'expense'): ?>
|
||
<option value="<?= (int)$c->id ?>"><?= htmlspecialchars($c->title, ENT_QUOTES, 'UTF-8') ?></option>
|
||
<?php endif; ?>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
<input type="number" step="0.01" min="0" max="100" class="form-control" name="formula_pct" placeholder="Процент">
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer" style="border-color:var(--surface-3)">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal fade" id="group-modal" tabindex="-1" data-bs-theme="dark">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content" style="background:var(--surface-2);color:var(--ink);">
|
||
<form id="group-form" method="post">
|
||
<?= CSRF::field() ?>
|
||
<input type="hidden" name="id">
|
||
<input type="hidden" name="type" id="group-type">
|
||
<div class="modal-header" style="border-color:var(--surface-3)">
|
||
<h5 class="modal-title" id="group-modal-title">Новая группа</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div id="group-form-error" class="alert alert-danger" style="display:none"></div>
|
||
<div class="mb-3">
|
||
<label class="form-label">Название</label>
|
||
<input type="text" class="form-control" name="title" maxlength="128" required>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer" style="border-color:var(--surface-3)">
|
||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Отмена</button>
|
||
<button type="submit" class="btn btn-primary">Сохранить</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="modal fade" id="category-archive-modal" tabindex="-1" data-bs-theme="dark">
|
||
<div class="modal-dialog">
|
||
<div class="modal-content" style="background:var(--surface-2);color:var(--ink);">
|
||
<div class="modal-header" style="border-color:var(--surface-3)">
|
||
<h5 class="modal-title">Архив статей и групп</h5>
|
||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Закрыть"></button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<?php if (empty($archived_groups)): ?>
|
||
<div class="card-meta" style="font-size:11px;margin-bottom:6px">Групп в архиве нет</div>
|
||
<?php else: ?>
|
||
<div class="card-meta" style="font-size:11px;margin-bottom:6px">Группы</div>
|
||
<?php foreach ($archived_groups as $group): ?>
|
||
<div class="archive-row" data-id="<?= (int)$group->id ?>" data-title="<?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?>">
|
||
<div>
|
||
<div class="room-title"><svg class="ico ico-sm"><use href="#ic-folder"/></svg> <?= htmlspecialchars($group->title, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="room-sub"><?= $group->type === 'income' ? 'Доход' : 'Расход' ?></div>
|
||
</div>
|
||
<button type="button" class="btn btn-sm btn-outline-light js-group-restore" title="Восстановить">
|
||
<svg class="ico"><use href="#ic-undo"/></svg>
|
||
Восстановить
|
||
</button>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
|
||
<?php if (empty($archived)): ?>
|
||
<div class="card-meta" style="font-size:11px;margin:14px 0 6px">Статей в архиве нет</div>
|
||
<?php else: ?>
|
||
<div class="card-meta" style="font-size:11px;margin:14px 0 6px">Статьи</div>
|
||
<?php foreach ($archived as $category): ?>
|
||
<div class="archive-row" data-id="<?= (int)$category->id ?>" data-title="<?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?>">
|
||
<div>
|
||
<div class="room-title"><?= htmlspecialchars($category->title, ENT_QUOTES, 'UTF-8') ?></div>
|
||
<div class="room-sub"><?= $category->type === 'income' ? 'Доход' : 'Расход' ?></div>
|
||
</div>
|
||
<button type="button" class="btn btn-sm btn-outline-light js-category-restore" title="Восстановить">
|
||
<svg class="ico"><use href="#ic-undo"/></svg>
|
||
Восстановить
|
||
</button>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|