다크 대시보드를 그대로 인쇄하던 '단순 프린트지'를 화이트 A4 전문 보고서로 대체. ?format=print 로 브라우저 print-to-PDF 하면 표지·요약·차트·서명을 갖춘 정식 문서가 나온다. 설계 3안(경영진 브리프/보안증적/비주얼 애널리틱스) 병렬 → 종합 → 구현. 실제 브라우저 렌더로 6개 섹션 전부 검증. 구성: - 표지 마스트헤드: 대형 대상월 + 관제 판정 씰(SVG 원형 도장 — 데이터 자동 판정 安定/注意/警報)이 시그니처. 러닝 헤더/푸터(대외비·문서번호·시스템). - 01 경영 요약: 헤드라인 KPI 4(SMS신뢰성 게이지·총경보·누수·측정) + 자동 총평 내러티브. - 02 월간 지표: 경보·이벤트 / 온습도 측정 2열 정의형. - 03 추이(인라인 SVG): 일별 평균 온·습도(안전/고온/저온 밴드·임계선), 일별 경보 스택 막대(온습도=네이비 / 누수=적색 사선 해치 — 흑백 인쇄 구분). - 04 관제 지점별 상세 카드, 05 누수 사고 로그(지속시간·복구), 06 기준·주석 및 서명란. 구현: - 집계를 monthly_report_data.php(공유 include)로 추출 — HTML 조회·CSV·PDF 뷰가 단일 소스 사용(회귀 0: HTML 표 3행·요약 11카드·CSV 3행 렌더 확인). 일별 추이·누수 사고· 판정 파생은 인쇄 뷰 전용으로 추가. - monthly_report_print.php(A4 뷰) + report_charts.php(인라인 SVG 차트) + assets/report-print.css (@page A4·여백·page-break·running header/footer·print-color-adjust). app.css 다크 토큰과 격리(.report-paper 스코프, report-print.css 단독 링크). - 폐쇄망 준수: 외부 CDN/JS/폰트/PDF 라이브러리 0, 시스템 폰트, 인라인 SVG. - 보안: 신규 include 3파일 직접접근 가드 + .htaccess FilesMatch 차단(monthly_report.php 본체는 진입 페이지라 제외). sensor_label 라벨·htmlspecialchars 이스케이프.
332 lines
19 KiB
PHP
332 lines
19 KiB
PHP
<?php
|
|
// =============================================================================
|
|
// monthly_report_print.php - 월간 운영 보고서 · PDF 저장 전용 A4 문서 뷰
|
|
//
|
|
// monthly_report.php 의 ?format=print 분기에서 require 된다(단독 진입점 아님).
|
|
// 집계 변수는 monthly_report_data.php 가 이미 산출해 이 스코프에 있다:
|
|
// $month, $start_at, $end_at, $report_generated_at, $report_scope, $summary,
|
|
// $sensor_rows, $cal_days, $daily_temp, $daily_hum, $daily_metric_alerts,
|
|
// $daily_leak_alerts, $incidents, $has_incident_table, $unrecovered_leak,
|
|
// $verdict, $verdict_label, $verdict_reason
|
|
//
|
|
// app.css(다크 셸)는 링크하지 않는다 — assets/report-print.css 만 링크해 다크 토큰과
|
|
// 격리한다. 차트는 report_charts.php 의 인라인 SVG 서버렌더(폐쇄망: 외부 참조 0).
|
|
// 모든 동적 텍스트는 htmlspecialchars, 숫자는 fmt_num() 으로 출력한다.
|
|
// =============================================================================
|
|
|
|
if (!defined('APP_VERSION')) { exit; } // 직접 접근 차단(monthly_report.php 경유 전용)
|
|
|
|
require_once __DIR__ . '/report_charts.php';
|
|
|
|
// ── 표시용 파생값 ─────────────────────────────────────────────────────────────
|
|
$h = fn($s) => htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8');
|
|
|
|
$month_dot = str_replace('-', '.', $month); // 2026-06 → 2026.06
|
|
$year_n = (int)substr($month, 0, 4);
|
|
$month_n = (int)substr($month, 5, 2);
|
|
$doc_no = 'ENV-' . $month; // 문서번호
|
|
|
|
try {
|
|
$dt_last = new DateTime($end_at);
|
|
$dt_last->modify('-1 day');
|
|
$period_end = $dt_last->format('Y-m-d');
|
|
} catch (Throwable $e) {
|
|
$period_end = substr($end_at, 0, 10);
|
|
}
|
|
$period_start = substr($start_at, 0, 10);
|
|
|
|
// 관제 대상(설정 기준)
|
|
$metric_ids = defined('METRIC_SENSOR_IDS') ? METRIC_SENSOR_IDS : [];
|
|
$leak_ids = defined('LEAK_SENSOR_IDS') ? LEAK_SENSOR_IDS : [];
|
|
$scope_total = count(array_unique(array_merge($metric_ids, $leak_ids)));
|
|
|
|
$total_alerts = $summary['threshold_alerts'] + $summary['leak_alert'];
|
|
$incident_count = $has_incident_table ? count($incidents) : $summary['leak_alert'];
|
|
|
|
// verdict 색 클래스(요약 카드/문장)
|
|
$verdict_cls = 'is-' . ($verdict === 'alert' ? 'alert' : ($verdict === 'warn' ? 'warn' : 'ok'));
|
|
$verdict_color = rc_verdict_color($verdict);
|
|
|
|
// 자동 총평 한 줄
|
|
$auto_summary = sprintf(
|
|
'당월 온습도 측정 %s건 · 임계 경보 %d건 · 누수 감지 %d건이 집계되었으며, SMS 발송 신뢰성은 %d%%(%d건 중 실패 %d건)입니다.',
|
|
number_format($summary['metrics']),
|
|
$summary['threshold_alerts'],
|
|
$summary['leak_alert'],
|
|
$summary['sms_reliability_pct'],
|
|
$summary['total_sms'],
|
|
$summary['sms_fail']
|
|
);
|
|
|
|
// 센서(지점)별 판정 — 데이터 층 verdict 규칙과 동일(미복구 누수는 월 단위라 여기선 누수감지로 근사)
|
|
$sensor_verdict = function (array $s): array {
|
|
if ($s['leak_alert'] > 0 || $s['sms_fail'] > 0) { return ['alert', '경보']; }
|
|
if ($s['threshold_alerts'] > 0 || $s['device_offline'] > 0) { return ['warn', '주의']; }
|
|
return ['ok', '안정'];
|
|
};
|
|
|
|
// 임계 기준 문자열
|
|
$rh_low_txt = (METRIC_RH_LOW >= 0) ? (rc_fmt((float)METRIC_RH_LOW) . '%') : '비활성';
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>정보시설 관제 월간 운영 보고서 - <?= $h($month) ?></title>
|
|
<link rel="stylesheet" href="assets/report-print.css">
|
|
</head>
|
|
<body>
|
|
<div class="report-canvas">
|
|
|
|
<!-- 화면 전용 안내 + 툴바(인쇄 시 자동 숨김) -->
|
|
<div class="screen-toolbar screen-only">
|
|
<a class="ghost" href="monthly_report.php?month=<?= $h($month) ?>">← 조회 화면</a>
|
|
<button type="button" onclick="window.print()">PDF로 저장 / 인쇄</button>
|
|
<a class="ghost" href="dashboard.php">대시보드</a>
|
|
</div>
|
|
<div class="print-note screen-only">
|
|
이 화면은 <b>PDF 저장 전용 A4 보고서</b> 미리보기입니다. <b>Ctrl+P</b>(⌘P) → 대상 <b>“PDF로 저장”</b>,
|
|
용지 <b>A4</b>, 여백 <b>기본</b>, <b>“배경 그래픽”</b> 옵션을 켜 주세요. 페이지 번호가 필요하면 인쇄
|
|
대화상자의 <b>머리글/바닥글</b> 옵션을 사용하세요(폐쇄망 정책상 문서 내 자동 페이지번호는 미탑재).
|
|
</div>
|
|
|
|
<!-- 러닝 헤더(매 장 반복) -->
|
|
<div class="run-header">
|
|
<span><b>정보시설 관제 월간 운영 보고서</b> · <?= $h($month_dot) ?></span>
|
|
<span class="cls">대외비 (CONFIDENTIAL)</span>
|
|
</div>
|
|
<!-- 러닝 푸터(매 장 반복 — 문서번호·생성일시로 추적성 확보) -->
|
|
<div class="run-footer">
|
|
<span>문서번호 <?= $h($doc_no) ?> · 생성 <?= $h($report_generated_at) ?></span>
|
|
<span>서버실·문서고 온습도/누수 관제 시스템 <?= $h(APP_VERSION) ?></span>
|
|
</div>
|
|
|
|
<div class="report-paper">
|
|
<div class="report-body">
|
|
|
|
<!-- ═══════════ 1. 표지 마스트헤드 ═══════════ -->
|
|
<section class="cover">
|
|
<div class="cover-seal">
|
|
<?= render_verdict_seal($verdict, $verdict_label) ?>
|
|
<div class="seal-cap">종합 판정</div>
|
|
</div>
|
|
<div class="cover-eyebrow">정보시설 관제 · 온습도 / 누수</div>
|
|
<h1 class="cover-title">정보시설 관제<br>월간 운영 보고서</h1>
|
|
<p class="cover-sub">서버실 · 문서고 온습도 및 누수 모니터링 / SMS 경보 운영 결과</p>
|
|
|
|
<div class="cover-month"><?= $h($month_dot) ?></div>
|
|
<div class="cover-period">대상 기간 <?= $h($period_start) ?> ~ <?= $h($period_end) ?> (<?= $year_n ?>년 <?= $month_n ?>월)</div>
|
|
|
|
<div class="cover-scope">
|
|
<div class="scope-item">
|
|
<div class="k">관제 지점</div>
|
|
<div class="v"><?= (int)$scope_total ?>개소</div>
|
|
<div class="t">온습도 <?= count($metric_ids) ?> · 누수 <?= count($leak_ids) ?></div>
|
|
</div>
|
|
<div class="scope-item">
|
|
<div class="k">정보기반</div>
|
|
<div class="v">서버실(안)</div>
|
|
<div class="t">온습도 계측</div>
|
|
</div>
|
|
<div class="scope-item">
|
|
<div class="k">조직혁신 · 고객센터</div>
|
|
<div class="v">문서고 · 서버실(밖)</div>
|
|
<div class="t">누수 감시</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="doc-control">
|
|
<div><div class="dk">문서번호</div><div class="dv"><?= $h($doc_no) ?></div></div>
|
|
<div><div class="dk">생성 일시</div><div class="dv"><?= $h($report_generated_at) ?></div></div>
|
|
<div><div class="dk">문서 분류</div><div class="dv cls">대외비</div></div>
|
|
<div><div class="dk">보고 범위</div><div class="dv"><?= $h($report_scope) ?></div></div>
|
|
<div><div class="dk">데이터 출처</div><div class="dv">leak_sms_log · leak_sensor_metric</div></div>
|
|
<div><div class="dk">시스템</div><div class="dv">관제 <?= $h(APP_VERSION) ?></div></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ═══════════ 2. 경영 요약 ═══════════ -->
|
|
<section class="section page-break">
|
|
<div class="section-title"><span class="no">01</span> 경영 요약 <span class="en">EXECUTIVE SUMMARY</span></div>
|
|
|
|
<div class="kpi-row">
|
|
<div class="kpi-card is-ok">
|
|
<div class="kpi-gauge-wrap">
|
|
<?= render_uptime_gauge($summary['sms_reliability_pct'], $verdict_color, $summary['sms_reliability_pct'] . '%', 'SMS 신뢰성') ?>
|
|
</div>
|
|
</div>
|
|
<div class="kpi-card <?= $total_alerts > 0 ? 'is-warn' : 'is-ok' ?>">
|
|
<div class="kpi-k">총 경보</div>
|
|
<div class="kpi-v"><?= (int)$total_alerts ?></div>
|
|
<div class="kpi-s">임계 <?= (int)$summary['threshold_alerts'] ?> · 누수 <?= (int)$summary['leak_alert'] ?></div>
|
|
</div>
|
|
<div class="kpi-card <?= $summary['leak_alert'] > 0 ? 'is-alert' : 'is-ok' ?>">
|
|
<div class="kpi-k">누수 감지</div>
|
|
<div class="kpi-v"><?= (int)$summary['leak_alert'] ?></div>
|
|
<div class="kpi-s"><?= $has_incident_table ? ('사고 ' . (int)$incident_count . '건 · 미복구 ' . (int)$unrecovered_leak) : ('복구 ' . (int)$summary['leak_recovery'] . '건') ?></div>
|
|
</div>
|
|
<div class="kpi-card is-ok">
|
|
<div class="kpi-k">측정 건수</div>
|
|
<div class="kpi-v"><?= number_format($summary['metrics']) ?></div>
|
|
<div class="kpi-s">평균 <?= fmt_num($summary['avg_temp'], '℃') ?> / <?= fmt_num($summary['avg_humidity'], '%') ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="exec-summary">
|
|
<div class="verdict-line <?= $verdict_cls ?>">종합 판정: <?= $h($verdict_label) ?><?= $verdict_reason !== '' ? ' — ' . $h($verdict_reason) : '' ?></div>
|
|
<p><?= $h($auto_summary) ?></p>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ═══════════ 3. 월간 지표 상세 ═══════════ -->
|
|
<section class="section">
|
|
<div class="section-title"><span class="no">02</span> 월간 지표 상세 <span class="en">MONTHLY METRICS</span></div>
|
|
<div class="metric-grid">
|
|
<div class="metric-block">
|
|
<h3>경보 · 이벤트</h3>
|
|
<table class="def">
|
|
<tr><th>고온 경보</th><td><?= (int)$summary['high_temp'] ?>건</td></tr>
|
|
<tr><th>저온 경보</th><td><?= (int)$summary['low_temp'] ?>건</td></tr>
|
|
<tr><th>고습 경보</th><td><?= (int)$summary['high_humidity'] ?>건</td></tr>
|
|
<tr><th>저습 경보</th><td><?= (int)$summary['low_humidity'] ?>건</td></tr>
|
|
<tr><th>임계 경보 합계</th><td><?= (int)$summary['threshold_alerts'] ?>건</td></tr>
|
|
<tr><th>누수 감지 / 복구</th><td class="<?= $summary['leak_alert'] > 0 ? 'is-alert' : '' ?>"><?= (int)$summary['leak_alert'] ?> / <?= (int)$summary['leak_recovery'] ?>건</td></tr>
|
|
<tr><th>정상 복귀</th><td><?= (int)$summary['recovery'] ?>건</td></tr>
|
|
<tr><th>장비 오프라인 / 복구</th><td><?= (int)$summary['device_offline'] ?> / <?= (int)$summary['device_online'] ?>건</td></tr>
|
|
<tr><th>SMS 실패 / 총 발송</th><td class="<?= $summary['sms_fail'] > 0 ? 'is-alert' : '' ?>"><?= (int)$summary['sms_fail'] ?> / <?= (int)$summary['total_sms'] ?>건</td></tr>
|
|
</table>
|
|
</div>
|
|
<div class="metric-block">
|
|
<h3>온습도 측정</h3>
|
|
<table class="def">
|
|
<tr><th>측정 건수</th><td><?= number_format($summary['metrics']) ?>건</td></tr>
|
|
<tr><th>평균 온도</th><td><?= fmt_num($summary['avg_temp'], '℃') ?></td></tr>
|
|
<tr><th>온도 최저 / 최고</th><td><?= fmt_num($summary['min_temp'], '℃') ?> / <?= fmt_num($summary['max_temp'], '℃') ?></td></tr>
|
|
<tr><th>평균 습도</th><td><?= fmt_num($summary['avg_humidity'], '%') ?></td></tr>
|
|
<tr><th>습도 최저 / 최고</th><td><?= fmt_num($summary['min_humidity'], '%') ?> / <?= fmt_num($summary['max_humidity'], '%') ?></td></tr>
|
|
<tr><th>SMS 신뢰성</th><td><?= (int)$summary['sms_reliability_pct'] ?>%</td></tr>
|
|
<tr><th>고온 / 저온 임계</th><td><?= $h(rc_fmt((float)METRIC_TEMP_HIGH_C)) ?>℃ / <?= $h(rc_fmt((float)METRIC_TEMP_LOW_C)) ?>℃</td></tr>
|
|
<tr><th>고습 / 저습 임계</th><td><?= $h(rc_fmt((float)METRIC_RH_HIGH)) ?>% / <?= $h($rh_low_txt) ?></td></tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ═══════════ 4. 월중 추이(차트) ═══════════ -->
|
|
<section class="section">
|
|
<div class="section-title"><span class="no">03</span> 월중 추이 <span class="en">DAILY TRENDS</span></div>
|
|
|
|
<div class="chart-panel">
|
|
<h3>일별 평균 온·습도</h3>
|
|
<p class="chart-cap">임계 밴드(고온 적 · 안전 녹 · 저온 청)를 배경에 인쇄. 온도 실선(좌축) · 습도 파선(우축). 결측일은 선이 끊깁니다.</p>
|
|
<?= render_daily_temp_hum_line($cal_days, $daily_temp, $daily_hum) ?>
|
|
</div>
|
|
|
|
<div class="chart-panel">
|
|
<h3>일별 경보 발생</h3>
|
|
<p class="chart-cap">온습도 임계 경보(네이비)와 누수 감지(적 · 사선)를 당월 1일~말일 축에 스택으로 표시합니다.</p>
|
|
<?= render_daily_alert_bars($cal_days, $daily_metric_alerts, $daily_leak_alerts) ?>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ═══════════ 5. 관제 지점별 상세 ═══════════ -->
|
|
<section class="section">
|
|
<div class="section-title"><span class="no">04</span> 관제 지점별 상세 <span class="en">BY LOCATION</span></div>
|
|
<?php if (empty($sensor_rows)): ?>
|
|
<div class="chart-empty">해당 월 측정·경보 내역이 없습니다.</div>
|
|
<?php else: ?>
|
|
<div class="loc-cards">
|
|
<?php foreach ($sensor_rows as $s): [$sv_cls, $sv_lab] = $sensor_verdict($s); ?>
|
|
<div class="loc-card">
|
|
<div class="lc-head">
|
|
<div>
|
|
<div class="lc-name"><?= $h($s['sensor_name']) ?></div>
|
|
<div class="lc-loc"><?= $h($s['device_location']) ?></div>
|
|
</div>
|
|
<span class="pill is-<?= $sv_cls ?>"><?= $h($sv_lab) ?></span>
|
|
</div>
|
|
<dl>
|
|
<dt>임계 경보</dt><dd><?= (int)$s['threshold_alerts'] ?>건</dd>
|
|
<dt>고온/저온</dt><dd><?= (int)$s['high_temp'] ?>/<?= (int)$s['low_temp'] ?></dd>
|
|
<dt>고습/저습</dt><dd><?= (int)$s['high_humidity'] ?>/<?= (int)$s['low_humidity'] ?></dd>
|
|
<dt>누수 감지/복구</dt><dd class="<?= $s['leak_alert'] > 0 ? 'is-alert' : '' ?>"><?= (int)$s['leak_alert'] ?>/<?= (int)$s['leak_recovery'] ?></dd>
|
|
<dt>오프라인/복구</dt><dd><?= (int)$s['device_offline'] ?>/<?= (int)$s['device_online'] ?></dd>
|
|
<dt>SMS 실패</dt><dd class="<?= $s['sms_fail'] > 0 ? 'is-alert' : '' ?>"><?= (int)$s['sms_fail'] ?></dd>
|
|
<dt>측정</dt><dd><?= number_format($s['metrics']) ?>건</dd>
|
|
<dt>평균 온/습</dt><dd><?= fmt_num($s['avg_temp'], '℃') ?> / <?= fmt_num($s['avg_humidity'], '%') ?></dd>
|
|
<dt>온도 최저/최고</dt><dd><?= fmt_num($s['min_temp'], '℃') ?> / <?= fmt_num($s['max_temp'], '℃') ?></dd>
|
|
<dt>습도 최저/최고</dt><dd><?= fmt_num($s['min_humidity'], '%') ?> / <?= fmt_num($s['max_humidity'], '%') ?></dd>
|
|
<dt>최근 측정</dt><dd><?= $h($s['last_measured_at'] ?: '-') ?></dd>
|
|
</dl>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<!-- ═══════════ 6. 누수 사고 로그 ═══════════ -->
|
|
<section class="section">
|
|
<div class="section-title"><span class="no">05</span> 누수 사고 로그 <span class="en">LEAK INCIDENTS</span></div>
|
|
<?php if (!$has_incident_table): ?>
|
|
<div class="chart-empty">누수 사고 이력(leak_incident) 테이블이 도입되지 않은 배포입니다. SMS 태그 집계로 대체합니다 — 당월 누수 감지 <?= (int)$summary['leak_alert'] ?>건 / 복구 <?= (int)$summary['leak_recovery'] ?>건.</div>
|
|
<?php elseif (empty($incidents)): ?>
|
|
<div class="incident-none">✓ 당월 누수 사고 없음 (0건) — 감시 구간 내 누수 미발생.</div>
|
|
<?php else: ?>
|
|
<table class="grid">
|
|
<thead><tr><th>발생 일시</th><th>지점</th><th>위치</th><th>지속</th><th>상태</th></tr></thead>
|
|
<tbody>
|
|
<?php foreach ($incidents as $inc): ?>
|
|
<tr>
|
|
<td class="l"><?= $h($inc['started_at']) ?></td>
|
|
<td class="l"><?= $h($inc['sensor_name']) ?></td>
|
|
<td class="l"><?= $h($inc['device_location']) ?></td>
|
|
<td><?php
|
|
if ($inc['ongoing']) { echo '진행중'; }
|
|
elseif ($inc['duration_min'] !== null) {
|
|
$mm = (int)$inc['duration_min'];
|
|
echo $mm >= 60 ? intdiv($mm, 60) . '시간 ' . ($mm % 60) . '분' : $mm . '분';
|
|
} else { echo '-'; }
|
|
?></td>
|
|
<td class="<?= $inc['ongoing'] ? 'is-alert' : '' ?>"><?= $inc['ongoing'] ? '미복구' : '복구' ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
</section>
|
|
|
|
<!-- ═══════════ 7. 기준 · 주석 및 서명 ═══════════ -->
|
|
<section class="section">
|
|
<div class="section-title"><span class="no">06</span> 기준 · 주석 및 서명 <span class="en">BASIS & SIGN-OFF</span></div>
|
|
<div class="basis-grid">
|
|
<div class="basis-block">
|
|
<h3>판정 · 임계 기준</h3>
|
|
<ul>
|
|
<li><b>임계</b> 고온 <?= $h(rc_fmt((float)METRIC_TEMP_HIGH_C)) ?>℃ · 저온 <?= $h(rc_fmt((float)METRIC_TEMP_LOW_C)) ?>℃ · 고습 <?= $h(rc_fmt((float)METRIC_RH_HIGH)) ?>% · 저습 <?= $h($rh_low_txt) ?></li>
|
|
<li><b>판정 규칙</b> 미복구 누수 또는 SMS 실패 > 0 → 경보 · 임계 경보 또는 오프라인 발생 → 주의 · 그 외 → 안정</li>
|
|
<li><b>오프라인 판정</b> <?= (int)(HEARTBEAT_TIMEOUT_SEC / 60) ?>분 무수신 · <b>경보 쿨다운</b> 온습도 <?= (int)(METRIC_ALERT_COOLDOWN_SEC / 60) ?>분 / 누수 <?= (int)(LEAK_ALERT_COOLDOWN_SEC / 60) ?>분</li>
|
|
</ul>
|
|
</div>
|
|
<div class="basis-block">
|
|
<h3>데이터 · 주석</h3>
|
|
<ul>
|
|
<li><b>출처</b> leak_sms_log(태그 접두 집계) · leak_sensor_metric(측정) · leak_sensor_log/leak_incident(누수)</li>
|
|
<li><b>집계 범위</b> <?= $h($period_start) ?> 00:00 ~ <?= $h($period_end) ?> 24:00 (센서는 sensor_id 기준, 표시명은 관리주체 라벨)</li>
|
|
<li><b>개인정보</b> 수신번호는 표시 단계에서 마스킹(mask_phone) · 본 문서 분류: <span style="color:#b11f1f;font-weight:700">대외비</span></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="sign-row">
|
|
<div class="sign-box"><div class="sk">작성</div><div class="sv"></div><div class="sn">직/성명 · 일자</div></div>
|
|
<div class="sign-box"><div class="sk">검토</div><div class="sv"></div><div class="sn">직/성명 · 일자</div></div>
|
|
<div class="sign-box"><div class="sk">승인</div><div class="sv"></div><div class="sn">직/성명 · 일자</div></div>
|
|
</div>
|
|
</section>
|
|
|
|
</div><!-- /report-body -->
|
|
</div><!-- /report-paper -->
|
|
</div><!-- /report-canvas -->
|
|
</body>
|
|
</html>
|