- 사용자 매뉴얼: league/commonmark 기반 bag/manual(로그인 전용), ManualRenderer + Config\Manual manifest, 콘텐츠 8종, E2E - 번호알기(봉투번호확인): bag/number-lookup, BagNumberLookup, E2E - gov-portal 대시보드 시안(기본/strip)·기본코드관리 화면 - 메뉴 관리: 등록·수정 후 메뉴 화면 유지, 수정 버튼 클릭 시 상단 스크롤 - 수불/분석 리포트(LOT 수불·반품/파기·수급계획·추이) 표시 보강 - .gitignore: docs/ → /docs/ 앵커링(최상위 개발문서만 제외, app/Docs는 추적) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
105 lines
5.3 KiB
PHP
105 lines
5.3 KiB
PHP
<?php
|
|
$baseYear = (int) ($baseYear ?? (int) date('Y'));
|
|
$season = (string) ($season ?? 'spring');
|
|
$seasonLabel = (string) ($seasonLabel ?? '봄');
|
|
$seasonMonthsLabel = (string) ($seasonMonthsLabel ?? '');
|
|
$deviationMin = (float) ($deviationMin ?? 0);
|
|
$queried = (bool) ($queried ?? false);
|
|
$filters = is_array($filters ?? null) ? $filters : [];
|
|
$rows = is_array($rows ?? null) ? $rows : [];
|
|
$seasonCatalog = \App\Libraries\BagAnalyticsReportBuilder::seasonCatalog();
|
|
$seasonScope = $seasonMonthsLabel !== ''
|
|
? $baseYear . '년 ' . $seasonLabel . ' (' . $seasonMonthsLabel . ')'
|
|
: (string) $baseYear . '년 ' . $seasonLabel;
|
|
?>
|
|
<?= view('components/print_header', [
|
|
'printTitle' => '계절별 판매 추이 분석',
|
|
'printExtraLines' => ['기준: ' . $seasonScope, '(단위: 매)'],
|
|
]) ?>
|
|
|
|
<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 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">인쇄</button>
|
|
<a href="<?= base_url('dashboard') ?>" class="border border-gray-400 text-gray-700 px-3 py-1 rounded-sm text-sm">종료</a>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="p-2 bg-white border-b border-gray-200 no-print text-sm">
|
|
<form id="seasonal-trend-form" method="get" action="<?= site_url('bag/analytics/seasonal-trend') ?>" class="flex flex-wrap items-end gap-3">
|
|
<input type="hidden" name="search" value="1"/>
|
|
<div>
|
|
<label class="block text-gray-600 mb-0.5">기준년도</label>
|
|
<input type="number" name="base_year" value="<?= (int) $baseYear ?>" min="2000" max="2100" class="border border-gray-300 rounded px-2 py-1 min-w-[7rem] w-28"/>
|
|
</div>
|
|
<div>
|
|
<label class="block text-gray-600 mb-0.5">계절선택</label>
|
|
<select name="season" class="border border-gray-300 rounded px-2 py-1 min-w-[14rem] w-full max-w-[18rem]" onchange="this.form.submit()">
|
|
<?php foreach ($seasonCatalog as $val => $def): ?>
|
|
<option value="<?= esc($val, 'attr') ?>" <?= $season === $val ? 'selected' : '' ?>>
|
|
<?= esc((string) $def['label']) ?> (<?= esc((string) $def['months_label']) ?>)
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-gray-600 mb-0.5">편차</label>
|
|
<input type="number" name="deviation_min" value="<?= esc((string) $deviationMin) ?>" step="0.01" min="0" class="border border-gray-300 rounded px-2 py-1 w-28"/>
|
|
<span class="text-gray-500">% 이상(절대값)</span>
|
|
</div>
|
|
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm">조회</button>
|
|
</form>
|
|
<p class="text-xs text-gray-500 mt-1">
|
|
(단위: 매) · 계절을 바꾸면 자동 조회됩니다.
|
|
<?php if ($queried && $seasonMonthsLabel !== ''): ?>
|
|
· 현재: <strong><?= esc($seasonScope) ?></strong> <strong>판매(sale)</strong> 월평균(계절 3개월 합÷3, 반품·취소 제외) vs 전년 동일 계절
|
|
<?php endif; ?>
|
|
</p>
|
|
</section>
|
|
|
|
<div class="m-2 border border-gray-300">
|
|
<div class="bg-gray-100 px-3 py-1.5 text-sm font-bold border-b">
|
|
계절별 판매 추이 분석 조회 내역
|
|
<?php if ($queried): ?> — <?= esc($seasonScope) ?><?php endif; ?>
|
|
</div>
|
|
<div class="overflow-auto max-h-[28rem]">
|
|
<table class="w-full data-table text-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>대행소</th>
|
|
<th>지정판매소</th>
|
|
<th class="w-24">판매소번호</th>
|
|
<th class="w-20">성명</th>
|
|
<th class="w-24 text-right">전년 계절평균</th>
|
|
<th class="w-24 text-right">기준년 계절평균</th>
|
|
<th class="w-20 text-right">평균 차</th>
|
|
<th class="w-16 text-right">편차(%)</th>
|
|
<th class="w-24 text-center">지정일자</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (! $queried): ?>
|
|
<tr><td colspan="9" class="text-center text-gray-400 py-8">조회 조건 입력 후 조회</td></tr>
|
|
<?php elseif ($rows === []): ?>
|
|
<tr><td colspan="9" class="text-center text-gray-500 py-8">편차 조건(|%|)에 맞는 자료가 없습니다.</td></tr>
|
|
<?php endif; ?>
|
|
<?php foreach ($rows as $row): ?>
|
|
<tr>
|
|
<td class="text-left pl-2"><?= esc((string) ($row['agency_name'] ?? '')) ?></td>
|
|
<td class="text-left pl-2"><?= esc((string) ($row['shop_name'] ?? '')) ?></td>
|
|
<td class="text-center"><?= esc((string) ($row['shop_no'] ?? '')) ?></td>
|
|
<td class="text-center"><?= esc((string) ($row['rep_name'] ?? '')) ?></td>
|
|
<td class="text-right tabular-nums"><?= number_format((int) ($row['prev_season_avg'] ?? 0)) ?></td>
|
|
<td class="text-right tabular-nums"><?= number_format((int) ($row['base_season_avg'] ?? 0)) ?></td>
|
|
<td class="text-right tabular-nums"><?= number_format((int) ($row['avg_diff'] ?? 0)) ?></td>
|
|
<td class="text-right tabular-nums"><?= esc((string) ($row['deviation_pct'] ?? '0')) ?></td>
|
|
<td class="text-center"><?= esc((string) ($row['designated_at'] ?? '')) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|