Files
jongryangje/app/Views/admin/sales_report/yearly_sales.php

233 lines
9.9 KiB
PHP
Raw Normal View History

<?php
declare(strict_types=1);
/** @var int $year */
/** @var string $gugunCode */
/** @var int $saIdx */
/** @var list<object> $agencies */
/** @var list<array{code: string, name: string}> $gugunOptions */
/** @var list<array{id: string, label: string}> $colSpec */
/** @var list<array{name: string, lines: list<array<string,mixed>>}> $itemBlocks */
/** @var array{name: string, lines: list<array<string,mixed>>} $footerBlock */
/** @var bool $hasBsFee */
/** @var string $lgName */
/** @var string $gugunLabel */
/** @var string $agencyLabel */
/** @var list<string> $printExtraLines */
/** @var bool $hasYearlyData */
$yMax = (int) date('Y') + 1;
$yMin = 2020;
$exportParams = array_merge([
'year' => (string) ($year ?? date('Y')),
'export' => '1',
], array_filter([
'gugun_code' => (string) ($gugunCode ?? ''),
'sa_idx' => (int) ($saIdx ?? 0) > 0 ? (string) (int) ($saIdx ?? 0) : '',
], static fn ($v): bool => $v !== '' && $v !== null && $v !== 0));
$excelUrl = mgmt_url('reports/yearly-sales?' . http_build_query($exportParams));
$colCount = 2 + count($colSpec ?? []);
$nMetricCols = max(1, count($colSpec ?? []));
$metricColPct = round(86 / $nMetricCols, 4);
$fmtMeasureCell = static function (array $cell, string $measureKey, bool $hasBsFee): string {
if ($measureKey === 'fee' && ! $hasBsFee) {
return '—';
}
if ($measureKey === 'qty') {
return number_format((int) ($cell['qty'] ?? 0));
}
return number_format((int) round((float) ($cell[$measureKey] ?? 0)));
};
?>
<?= view('components/print_header', [
'printTitle' => ((int) ($year ?? date('Y'))) . '년 판매 현황',
'printExtraLines' => $printExtraLines ?? [],
]) ?>
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel no-print">
<div class="flex flex-wrap items-center justify-between gap-y-2">
<span class="text-sm font-bold text-gray-700"> 판매 현황</span>
<div class="flex flex-wrap gap-2">
<button type="button" onclick="window.print()" class="border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
<a href="<?= esc($excelUrl, 'attr') ?>" class="inline-flex items-center border border-green-600 text-green-700 px-3 py-1 rounded-sm text-sm hover:bg-green-50 transition">엑셀저장</a>
</div>
</div>
</section>
<section class="p-3 bg-white border-b border-gray-200 no-print">
<form method="GET" action="<?= mgmt_url('reports/yearly-sales') ?>" class="flex flex-wrap items-end gap-3 text-sm">
<div>
<label class="block text-gray-600 mb-0.5">조회 년도</label>
<select name="year" class="border border-gray-300 rounded px-2 py-1 text-sm min-w-[7rem]">
<?php for ($y = $yMax; $y >= $yMin; $y--): ?>
<option value="<?= $y ?>" <?= (int) ($year ?? date('Y')) === $y ? 'selected' : '' ?>><?= $y ?>년</option>
<?php endfor; ?>
</select>
</div>
<div>
<label class="block text-gray-600 mb-0.5">구·군</label>
<select name="gugun_code" class="border border-gray-300 rounded px-2 py-1 text-sm min-w-[10rem] max-w-[18rem]">
<option value="">전체</option>
<?php foreach ($gugunOptions ?? [] as $g): ?>
<?php $gc = (string) ($g['code'] ?? ''); ?>
<option value="<?= esc($gc, 'attr') ?>" <?= ($gugunCode ?? '') === $gc ? 'selected' : '' ?>><?= esc((string) ($g['name'] ?? $gc)) ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-gray-600 mb-0.5">대행소</label>
<select name="sa_idx" class="border border-gray-300 rounded px-2 py-1 text-sm min-w-[12rem] max-w-[20rem]">
<option value="0">전체</option>
<?php foreach ($agencies ?? [] as $agency): ?>
<?php $aid = (int) ($agency->sa_idx ?? 0); ?>
<option value="<?= esc((string) $aid) ?>" <?= (int) ($saIdx ?? 0) === $aid ? 'selected' : '' ?>>
<?= esc(trim((string) ($agency->sa_name ?? ''))) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm">조회</button>
</form>
</section>
<section class="p-3 bg-white yearly-sales-report-section">
<style>
/* 화면: 가로 스크롤. 인쇄: 가로 용지 + 작은 글자 + 셀 줄바꿈으로 한 페이지에 맞춤 */
@media print {
@page {
size: A4 landscape;
margin: 5mm 6mm;
}
.yearly-sales-report-section {
padding: 0 !important;
}
.yearly-sales-scroll-wrap {
overflow: visible !important;
border: 1px solid #333 !important;
max-width: none !important;
}
#yearly-sales-table {
font-size: 7pt !important;
width: 100% !important;
max-width: 100% !important;
table-layout: fixed !important;
}
#yearly-sales-table th,
#yearly-sales-table td {
min-width: 0 !important;
max-width: none !important;
padding: 1px 2px !important;
white-space: normal !important;
word-break: break-word;
overflow-wrap: anywhere;
line-height: 1.15;
vertical-align: top;
}
#yearly-sales-table th {
font-size: 6.5pt !important;
font-weight: 700;
}
}
@media screen {
#yearly-sales-table td.tabular-nums {
white-space: nowrap;
}
}
</style>
<div class="mb-2 text-center no-print">
<h1 class="text-lg font-bold m-0"><?= (int) ($year ?? date('Y')) ?>년 판매 현황</h1>
<p class="text-sm text-gray-700 m-1"><?= esc(trim(($lgName ?? '') . ' · 구·군: ' . ($gugunLabel ?? '') . ' · 대행소: ' . ($agencyLabel ?? ''))) ?></p>
<p class="text-xs text-gray-500 m-0">(단위: / )</p>
</div>
<div class="yearly-sales-scroll-wrap border border-gray-300 overflow-x-auto">
<table class="w-full data-table text-xs sm:text-sm" id="yearly-sales-table">
<colgroup>
<col style="width: 9%;"/>
<col style="width: 5%;"/>
<?php foreach (($colSpec ?? []) as $_): ?>
<col style="width: <?= esc((string) $metricColPct, 'attr') ?>%;"/>
<?php endforeach; ?>
</colgroup>
<thead>
<tr>
<th class="align-middle min-w-0 sm:min-w-[7rem] max-w-[10rem] sm:max-w-[12rem] text-left pl-2">품목</th>
<th class="align-middle min-w-0 sm:min-w-[4.5rem]">구분</th>
<?php foreach ($colSpec ?? [] as $col): ?>
<th class="align-middle text-center min-w-0 sm:min-w-[4.5rem] border-l border-gray-200"><?= esc((string) ($col['label'] ?? '')) ?></th>
<?php endforeach; ?>
</tr>
</thead>
<tbody class="text-right">
<?php if (! ($hasYearlyData ?? false)): ?>
<tr>
<td colspan="<?= (int) $colCount ?>" class="text-center text-gray-400 py-6">조회된 데이터가 없습니다.</td>
</tr>
<?php else: ?>
<?php foreach ($itemBlocks ?? [] as $block): ?>
<?php $lines = $block['lines'] ?? []; ?>
<?php foreach ($lines as $liIdx => $li): ?>
<tr class="odd:bg-white even:bg-gray-50/80">
<?php if ($liIdx === 0): ?>
<td rowspan="4" class="text-left align-top pl-2 pt-1 font-medium border-r border-gray-200"><?= esc((string) ($block['name'] ?? '')) ?></td>
<?php endif; ?>
<td class="text-left pl-2 border-r border-gray-100"><?= esc((string) ($li['measure'] ?? '')) ?></td>
<?php
$cells = (array) ($li['cells'] ?? []);
$mk = (string) ($li['measureKey'] ?? '');
?>
<?php foreach ($colSpec ?? [] as $col): ?>
<?php $cid = (string) ($col['id'] ?? ''); ?>
<?php $cell = (array) ($cells[$cid] ?? ['qty' => 0, 'amt' => 0.0, 'fee' => 0.0, 'levy' => 0.0]); ?>
<td class="border-l border-gray-100 tabular-nums"><?= $fmtMeasureCell($cell, $mk, (bool) ($hasBsFee ?? false)) ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php $fLines = $footerBlock['lines'] ?? []; ?>
<?php foreach ($fLines as $fIdx => $li): ?>
<tr class="bg-amber-50 font-semibold border-t-2 border-amber-200">
<?php if ($fIdx === 0): ?>
<td rowspan="4" class="text-center align-middle text-amber-900 border-r border-amber-200"><?= esc((string) ($footerBlock['name'] ?? '전체 합계')) ?></td>
<?php endif; ?>
<td class="text-left pl-2 border-r border-amber-100"><?= esc((string) ($li['measure'] ?? '')) ?></td>
<?php
$cells = (array) ($li['cells'] ?? []);
$mk = (string) ($li['measureKey'] ?? '');
?>
<?php foreach ($colSpec ?? [] as $col): ?>
<?php $cid = (string) ($col['id'] ?? ''); ?>
<?php $cell = (array) ($cells[$cid] ?? ['qty' => 0, 'amt' => 0.0, 'fee' => 0.0, 'levy' => 0.0]); ?>
<td class="border-l border-amber-100 tabular-nums"><?= $fmtMeasureCell($cell, $mk, (bool) ($hasBsFee ?? false)) ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
<script>
(function () {
const year = <?= json_encode((int) ($year ?? (int) date('Y')), JSON_THROW_ON_ERROR) ?>;
let savedTitle = document.title;
function stamp() {
const d = new Date();
const p = (n) => String(n).padStart(2, '0');
return d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) + '_' + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds());
}
window.addEventListener('beforeprint', function () {
savedTitle = document.title;
document.title = '년판매현황_' + year + '_' + stamp();
});
window.addEventListener('afterprint', function () {
document.title = savedTitle;
});
})();
</script>