feat: Flask 애플리케이션 모듈화 및 웹 대시보드 구현

- Flask Blueprint 아키텍처로 전환 (dashboard, upload, backup, status)
- app.py 681줄  95줄로 축소 (86% 감소)
- HTML 템플릿 모듈화 (base.html + 기능별 templates)
- CSS/JS 파일 분리 (common + 기능별 파일)
- 대시보드 기능 추가 (통계, 주간 예보, 방문객 추이)
- 파일 업로드 웹 인터페이스 구현
- 백업/복구 관리 UI 구현
- Docker 배포 환경 개선
- .gitignore 업데이트 (uploads, backups, cache 등)
This commit is contained in:
2025-12-26 17:31:37 +09:00
parent 9dab27529d
commit 7121f250bc
46 changed files with 6345 additions and 191 deletions

View File

@ -0,0 +1,108 @@
{% 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 %}