""" 목표 진행률 위젯. 월 연장근무 상한 + 일평균 목표를 stats_view 또는 메인에 표시. 설정값이 0이면 비활성 (위젯 자체 hide). """ from __future__ import annotations from datetime import datetime, date from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QProgressBar from PyQt5.QtCore import Qt class GoalWidget(QWidget): """월간 목표 진행률 표시.""" def __init__(self, db, parent=None): super().__init__(parent) self.db = db layout = QVBoxLayout() layout.setContentsMargins(8, 6, 8, 6) layout.setSpacing(4) title = QLabel("🎯 이번 달 목표") title.setStyleSheet("font-weight: bold;") layout.addWidget(title) # 연장근무 상한 ot_row = QHBoxLayout() self.ot_label = QLabel("연장근무:") self.ot_label.setFixedWidth(100) self.ot_bar = QProgressBar() self.ot_bar.setTextVisible(True) self.ot_bar.setFixedHeight(18) ot_row.addWidget(self.ot_label) ot_row.addWidget(self.ot_bar, 1) layout.addLayout(ot_row) # 일평균 avg_row = QHBoxLayout() self.avg_label = QLabel("일평균:") self.avg_label.setFixedWidth(100) self.avg_bar = QProgressBar() self.avg_bar.setTextVisible(True) self.avg_bar.setFixedHeight(18) avg_row.addWidget(self.avg_label) avg_row.addWidget(self.avg_bar, 1) layout.addLayout(avg_row) self.setLayout(layout) def refresh(self): """현재 설정값과 이번 달 통계로 진행률 갱신. 0=비활성 시 row 숨김.""" try: ot_target = int(self.db.get_setting('goal_overtime_max_monthly', '0') or 0) avg_target = float(self.db.get_setting('goal_avg_hours_daily', '0') or 0) except (ValueError, TypeError): ot_target, avg_target = 0, 0.0 # 둘 다 비활성이면 위젯 자체 숨김 if ot_target <= 0 and avg_target <= 0: self.setVisible(False) return self.setVisible(True) now = datetime.now() stats = self.db.get_monthly_stats(now.year, now.month) ot_total = (stats.get('total_overtime_minutes') or 0) total_h = stats.get('total_hours') or 0 work_days = stats.get('work_days') or 1 # 연장근무 상한 (낮을수록 좋음) if ot_target > 0: self.ot_label.setVisible(True) self.ot_bar.setVisible(True) self.ot_bar.setMaximum(ot_target) self.ot_bar.setValue(min(ot_total, ot_target)) ratio = ot_total / ot_target if ot_target else 0 ot_h, ot_m = ot_total // 60, ot_total % 60 tg_h, tg_m = ot_target // 60, ot_target % 60 self.ot_bar.setFormat(f"{ot_h}h {ot_m}m / {tg_h}h {tg_m}m") color = '#4caf50' if ratio < 0.6 else ('#ff9800' if ratio < 1.0 else '#f44336') self.ot_bar.setStyleSheet(f"QProgressBar::chunk {{ background-color: {color}; }}") else: self.ot_label.setVisible(False) self.ot_bar.setVisible(False) # 일평균 (목표 시간보다 적으면 좋음) if avg_target > 0: self.avg_label.setVisible(True) self.avg_bar.setVisible(True) avg = total_h / work_days if work_days else 0 self.avg_bar.setMaximum(int(avg_target * 100)) self.avg_bar.setValue(int(min(avg, avg_target) * 100)) self.avg_bar.setFormat(f"{avg:.1f}h / {avg_target:.1f}h") ratio = avg / avg_target if avg_target else 0 color = '#4caf50' if ratio < 0.9 else ('#ff9800' if ratio < 1.1 else '#f44336') self.avg_bar.setStyleSheet(f"QProgressBar::chunk {{ background-color: {color}; }}") else: self.avg_label.setVisible(False) self.avg_bar.setVisible(False)