- Flask Blueprint 아키텍처로 전환 (dashboard, upload, backup, status) - app.py 681줄 95줄로 축소 (86% 감소) - HTML 템플릿 모듈화 (base.html + 기능별 templates) - CSS/JS 파일 분리 (common + 기능별 파일) - 대시보드 기능 추가 (통계, 주간 예보, 방문객 추이) - 파일 업로드 웹 인터페이스 구현 - 백업/복구 관리 UI 구현 - Docker 배포 환경 개선 - .gitignore 업데이트 (uploads, backups, cache 등)
109 lines
4.2 KiB
HTML
109 lines
4.2 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}대시보드 - First Garden POS{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<link href="{{ url_for('static', filename='css/dashboard.css') }}" rel="stylesheet">
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="tab-pane fade show active" id="dashboard-panel" role="tabpanel">
|
|
<!-- 통계 카드 -->
|
|
<div class="row">
|
|
<div class="col-md-6 col-lg-3">
|
|
<div class="stat-card okpos-product">
|
|
<h3>OKPOS 상품별</h3>
|
|
<div class="stat-value" id="okpos-product-count">-</div>
|
|
<div class="stat-label">총 데이터</div>
|
|
<div class="stat-label" id="okpos-product-days">-</div>
|
|
<div class="stat-date" id="okpos-product-date">최종: -</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 col-lg-3">
|
|
<div class="stat-card okpos-receipt">
|
|
<h3>OKPOS 영수증</h3>
|
|
<div class="stat-value" id="okpos-receipt-count">-</div>
|
|
<div class="stat-label">총 데이터</div>
|
|
<div class="stat-label" id="okpos-receipt-days">-</div>
|
|
<div class="stat-date" id="okpos-receipt-date">최종: -</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 col-lg-3">
|
|
<div class="stat-card upsolution">
|
|
<h3>UPSolution</h3>
|
|
<div class="stat-value" id="upsolution-count">-</div>
|
|
<div class="stat-label">총 데이터</div>
|
|
<div class="stat-label" id="upsolution-days">-</div>
|
|
<div class="stat-date" id="upsolution-date">최종: -</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 col-lg-3">
|
|
<div class="stat-card weather">
|
|
<h3>날씨 데이터</h3>
|
|
<div class="stat-value" id="weather-count">-</div>
|
|
<div class="stat-label">총 데이터</div>
|
|
<div class="stat-label" id="weather-days">-</div>
|
|
<div class="stat-date" id="weather-date">최종: -</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 주간 예보 테이블 -->
|
|
<div style="margin-top: 30px;">
|
|
<h5 style="margin-bottom: 20px; font-weight: 600; color: #333;">
|
|
<i class="bi bi-calendar-event"></i> 이번주 예상 날씨 & 방문객
|
|
</h5>
|
|
<div class="table-responsive">
|
|
<table class="table table-hover">
|
|
<thead>
|
|
<tr>
|
|
<th>날짜</th>
|
|
<th>최저기온</th>
|
|
<th>최고기온</th>
|
|
<th>강수량</th>
|
|
<th>습도</th>
|
|
<th>예상 방문객</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="weekly-forecast-table">
|
|
<tr>
|
|
<td colspan="6" class="text-center text-muted">데이터 로딩 중...</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 방문객 추이 그래프 -->
|
|
<div style="margin-top: 30px;">
|
|
<h5 style="margin-bottom: 20px; font-weight: 600; color: #333;">
|
|
<i class="bi bi-graph-up"></i> 방문객 추이
|
|
</h5>
|
|
|
|
<!-- 날짜 범위 선택 -->
|
|
<div class="date-range-picker">
|
|
<input type="date" id="trend-start-date" class="form-control" style="max-width: 150px;">
|
|
<span style="display: flex; align-items: center;">~</span>
|
|
<input type="date" id="trend-end-date" class="form-control" style="max-width: 150px;">
|
|
<button class="btn btn-primary btn-sm" onclick="loadVisitorTrend()">조회</button>
|
|
<button class="btn btn-outline-primary btn-sm" onclick="resetTrendDate()">최근 1개월</button>
|
|
</div>
|
|
|
|
<!-- 그래프 -->
|
|
<div class="chart-container">
|
|
<canvas id="visitor-trend-chart"></canvas>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script src="{{ url_for('static', filename='js/dashboard.js') }}"></script>
|
|
<script>
|
|
// 대시보드 초기화
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
initializeDashboard();
|
|
});
|
|
</script>
|
|
{% endblock %}
|