Drobnosti GUI + sloupeček Stav v Obvodech

master
Kowalski 2026-10-11 21:41:15 +02:00
parent 0e18b46a15
commit acbdb6ba83
5 changed files with 136 additions and 4 deletions

View File

@ -61,6 +61,7 @@
<a class='nav-link' n:href=":Sign:out">Odhlásit</a> <a class='nav-link' n:href=":Sign:out">Odhlásit</a>
{else} {else}
<a class='nav-link' n:href=':Home:'>Home</a> <a class='nav-link' n:href=':Home:'>Home</a>
<a class='nav-link' n:href=':Nastaveni:'>Nastavení</a>
<a class='nav-link' n:href=":Sign:in, backlink: (isset($navrat) ? $navrat : '')">Přihlásit</a> <a class='nav-link' n:href=":Sign:in, backlink: (isset($navrat) ? $navrat : '')">Přihlásit</a>
{/if} {/if}
</div> </div>

View File

@ -5,13 +5,20 @@ declare(strict_types=1);
namespace App\Presentation\Nastaveni; namespace App\Presentation\Nastaveni;
use App\Core\MapovyPodklad; use App\Core\MapovyPodklad;
use App\Presentation\BasePresenter;
use Nette\Application\UI\Form; use Nette\Application\UI\Form;
use Nette\Application\UI\Presenter;
use Nette\Utils\ArrayHash; use Nette\Utils\ArrayHash;
final class NastaveniPresenter extends BasePresenter final class NastaveniPresenter extends Presenter
{ {
public function beforeRender(): void
{
if (!$this->getUser()->isLoggedIn()) {
$this->template->navrat = $this->storeRequest();
}
}
protected function createComponentPodkladForm(): Form protected function createComponentPodkladForm(): Form
{ {
$form = new Form; $form = new Form;

View File

@ -7,6 +7,7 @@ namespace App\Presentation\Obvod;
use App\Model\ObvodFacade; use App\Model\ObvodFacade;
use App\Model\ZaznamFacade; use App\Model\ZaznamFacade;
use App\Presentation\BasePresenter; use App\Presentation\BasePresenter;
use App\Presentation\Mapa\MapaPresenter;
use Nette; use Nette;
use Nette\Application\UI\Form; use Nette\Application\UI\Form;
use Nette\Application\UI\Multiplier; use Nette\Application\UI\Multiplier;
@ -40,9 +41,21 @@ final class ObvodPresenter extends BasePresenter
public function renderList(): void public function renderList(): void
{ {
$stari = $this->zaznam->getStariObvodu();
$obvody = [];
foreach ($this->obvod->getObvody($this->skupina) as $obvod) {
$info = $stari[(int) $obvod->CISLO] ?? null;
$obvody[] = (object) [
'ID' => (int) $obvod->ID,
'CISLO' => (int) $obvod->CISLO,
'NAZEV' => (string) $obvod->NAZEV,
'stav' => $this->stavObvodu($info),
];
}
$this->template->skupina = $this->skupina; $this->template->skupina = $this->skupina;
$this->template->skupiny = $this->obvod->getSkupiny(); $this->template->skupiny = $this->obvod->getSkupiny();
$this->template->obvody = $this->obvod->getObvody($this->skupina); $this->template->obvody = $obvody;
} }
public function renderView(int $id = null): void public function renderView(int $id = null): void
@ -198,6 +211,86 @@ final class ObvodPresenter extends BasePresenter
}); });
} }
/**
* @param array{mesice: int|null, probiha: bool, prideleni: int|null}|null $info
* @return object{popisek: string, barva: string, text: string}
*/
private function stavObvodu(?array $info): object
{
if ($info !== null && $info['probiha']) {
$mesice = $info['prideleni'];
return (object) [
'popisek' => 'Rozpracován ' . $this->textMesicu($mesice),
'barva' => $this->cssBarva($this->barvaStari($mesice, MapaPresenter::STUPNICE_PRIDELENI)),
'text' => $this->cssBarva($this->barvaTextu($mesice, MapaPresenter::STUPNICE_PRIDELENI)),
];
}
if ($info !== null && $info['mesice'] !== null) {
return (object) [
'popisek' => 'Nepropracován ' . $this->textMesicu($info['mesice']),
'barva' => $this->cssBarva($this->barvaStari($info['mesice'], MapaPresenter::STUPNICE_MESICU)),
'text' => $this->cssBarva($this->barvaTextu($info['mesice'], MapaPresenter::STUPNICE_MESICU)),
];
}
return (object) [
'popisek' => 'Bez záznamu',
'barva' => '#b0bec5',
'text' => '#1a1a1a',
];
}
private function cssBarva(string $barva): string
{
if (preg_match('/^rgb\((?:25[0-5]|2[0-4]\d|1?\d?\d),(?:25[0-5]|2[0-4]\d|1?\d?\d),(?:25[0-5]|2[0-4]\d|1?\d?\d)\)$/', $barva)) {
return $barva;
}
if (preg_match('/^#[0-9a-fA-F]{3}(?:[0-9a-fA-F]{3})?$/', $barva)) {
return $barva;
}
return '#b0bec5';
}
private function textMesicu(?int $mesice): string
{
return $mesice === null ? '—' : $mesice . ' měs.';
}
private function barvaStari(?int $mesice, int $max): string
{
$t = $mesice === null || $max <= 0 ? 1 : max(0, min($mesice / $max, 1));
$zelena = [27, 158, 62];
$zluta = [230, 184, 0];
$cervena = [198, 40, 40];
$kanaly = $t < 0.5
? $this->mixBarvy($zelena, $zluta, $t / 0.5)
: $this->mixBarvy($zluta, $cervena, ($t - 0.5) / 0.5);
return 'rgb(' . implode(',', $kanaly) . ')';
}
private function barvaTextu(?int $mesice, int $max): string
{
$t = $mesice === null || $max <= 0 ? 1 : max(0, min($mesice / $max, 1));
return $t > 0.72 ? '#fff' : '#1a1a1a';
}
/**
* @param array{0: int, 1: int, 2: int} $a
* @param array{0: int, 1: int, 2: int} $b
* @return array{0: int, 1: int, 2: int}
*/
private function mixBarvy(array $a, array $b, float $t): array
{
return [
(int) round($a[0] + ($b[0] - $a[0]) * $t),
(int) round($a[1] + ($b[1] - $a[1]) * $t),
(int) round($a[2] + ($b[2] - $a[2]) * $t),
];
}
private function obvodId(): int private function obvodId(): int
{ {
$id = $this->getParameter('id'); $id = $this->getParameter('id');

View File

@ -19,14 +19,16 @@
<tr> <tr>
<th scope="col">Číslo</th> <th scope="col">Číslo</th>
<th scope="col">Název</th> <th scope="col">Název</th>
<th scope="col">Stav</th>
<th scope="col">Akce</th> <th scope="col">Akce</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{foreach $obvody as $obvod} {foreach $obvody as $obvod}
<tr> <tr>
<td data-popisek="Číslo">{$obvod->CISLO}</td> <td data-popisek="Číslo"><span class="tabulka-cislo">{$obvod->CISLO}</span></td>
<td data-popisek="Název">{$obvod->NAZEV}</td> <td data-popisek="Název">{$obvod->NAZEV}</td>
<td data-popisek="Stav"><span class="stav-badge" style="background: {$obvod->stav->barva|noescape}; color: {$obvod->stav->text|noescape}">{$obvod->stav->popisek}</span></td>
<td class="bunka-akce" data-popisek="Akce"> <td class="bunka-akce" data-popisek="Akce">
<div class="akce-radek"> <div class="akce-radek">
<a n:href=":Obvod:view id:$obvod->ID" class="tlacitko">Otevřít</a> <a n:href=":Obvod:view id:$obvod->ID" class="tlacitko">Otevřít</a>

View File

@ -786,6 +786,35 @@ body:has(#map[data-max]) {
border-bottom: 0; border-bottom: 0;
} }
.tabulka-cislo {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.75rem;
height: 2.75rem;
flex: 0 0 auto;
border-radius: 50%;
border: 2px solid #1d4f91;
background: #2652a8;
color: #fff;
font-size: 1.05rem;
font-weight: 800;
line-height: 1;
box-shadow: 0 4px 10px rgba(29, 79, 145, 0.28);
}
.stav-badge {
display: inline-block;
padding: 0.28rem 0.7rem;
border-radius: 999px;
border: 1px solid rgba(0, 0, 0, 0.22);
font-size: 0.82rem;
font-weight: 800;
line-height: 1.2;
white-space: nowrap;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
.bunka-akce .akce-radek { .bunka-akce .akce-radek {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;