From a7a294ce93dabc8c93907aef8d68b3b284e8d21d Mon Sep 17 00:00:00 2001 From: king Date: Wed, 16 Sep 2026 00:14:40 +0900 Subject: [PATCH] =?UTF-8?q?feat(project):=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EB=8B=AC=EB=A0=A5=EC=97=90=202026~2030=20=EB=8C=80?= =?UTF-8?q?=ED=95=9C=EB=AF=BC=EA=B5=AD=20=EA=B3=B5=ED=9C=B4=EC=9D=BC=C2=B7?= =?UTF-8?q?=EB=8C=80=EC=B2=B4=EA=B3=B5=ED=9C=B4=EC=9D=BC=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit vacation 모듈은 공휴일을 vacation_db 테이블로 관리하지만 휴가일수 계산용 으로 강하게 결합돼 있어(조사 결과 공용 provider 없음), project 달력은 "보여주기만" 하면 되므로 store.py 에 정적 KR_HOLIDAYS 표(날짜→이름)를 추가하는 방식으로 처리 — 새 DB 연결/마이그레이션 없음. - 신정·설날·삼일절·어린이날·부처님오신날·현충일·광복절·추석·개천절· 한글날·성탄절 + 실제 "관공서의 공휴일에 관한 규정" 대체공휴일 규칙 그대로 반영(설날/추석/어린이날/삼일절/광복절/개천절/한글날/부처님오신 날/성탄절 대상, 신정·현충일은 대체 없음). 근로자의 날·제헌절은 관공서 공휴일이 아니라서 제외(vacation 모듈 2026년 기존 시드와 동일 기준). 선거일 같은 임시공휴일은 범위 밖. - 웹 검색으로 확보한 2027~2030년 데이터를 파이썬 요일 계산으로 전수 검증(90건 전부 일치) — 날짜 오타 위험 제거. - 달력 날짜 칸: 공휴일이면 일요일과 같은 빨간색 + 이름 라벨 표시, 호버 시 툴팁(title)도 함께 제공. Co-Authored-By: Claude Sonnet 5 --- app/modules/project/router.py | 1 + app/modules/project/store.py | 84 +++++++++++++++++++ .../project/templates/project/inbox.html | 2 +- .../project/templates/project/index.html | 2 +- .../project/templates/project/project.html | 7 +- app/static/project.css | 4 + 6 files changed, 95 insertions(+), 5 deletions(-) diff --git a/app/modules/project/router.py b/app/modules/project/router.py index 30645ad..aeb9929 100644 --- a/app/modules/project/router.py +++ b/app/modules/project/router.py @@ -285,6 +285,7 @@ def _build_task_calendar( "is_today": d == today, "is_sunday": d.weekday() == 6, "is_saturday": d.weekday() == 5, + "holiday_name": store.holiday_name(d.isoformat()), } for d in week ] diff --git a/app/modules/project/store.py b/app/modules/project/store.py index aa0e323..e46ddc8 100644 --- a/app/modules/project/store.py +++ b/app/modules/project/store.py @@ -49,6 +49,90 @@ COLOR_PALETTE: tuple[str, ...] = ( "#5a6772", # slate ) +# ════════════════════════════════════════════════════════════ +# 대한민국 국경일·공휴일(2026~2030) — 프로젝트 달력 표시 전용. +# +# vacation 모듈도 공휴일을 관리하지만(vacation_holidays 테이블) 그건 +# 휴가 일수 계산용으로 vacation_db 에 강하게 결합돼 있고, 여기는 달력에 +# 빨간 글씨로 "보여만" 주면 되는 용도라 별도 DB 연결 없이 정적 표로 둔다. +# 근로자의 날(5/1)·제헌절(7/17)은 관공서 공휴일이 아니라서 제외했다 +# (vacation 모듈의 기존 2026년 시드와 동일 기준). 대체공휴일은 실제 +# "관공서의 공휴일에 관한 규정" 대체공휴일 규정을 그대로 반영함(설날· +# 추석·어린이날·삼일절/광복절/개천절/한글날·부처님오신날·성탄절 대상, +# 신정·현충일은 대체 없음). 새 연도가 필요하면 이 표에 추가한다. +# ════════════════════════════════════════════════════════════ +KR_HOLIDAYS: dict[str, str] = { + # 2026 + "2026-01-01": "신정", + "2026-02-16": "설날 연휴", "2026-02-17": "설날", "2026-02-18": "설날 연휴", + "2026-03-01": "삼일절", "2026-03-02": "삼일절 대체", + "2026-05-05": "어린이날", + "2026-05-24": "부처님오신날", "2026-05-25": "부처님오신날 대체", + "2026-06-06": "현충일", + "2026-08-15": "광복절", "2026-08-17": "광복절 대체", + "2026-09-24": "추석 연휴", "2026-09-25": "추석", "2026-09-26": "추석 연휴", + "2026-09-28": "추석 대체", + "2026-10-03": "개천절", "2026-10-05": "개천절 대체", + "2026-10-09": "한글날", + "2026-12-25": "성탄절", + # 2027 + "2027-01-01": "신정", + "2027-02-06": "설날 연휴", "2027-02-07": "설날", "2027-02-08": "설날 연휴", + "2027-02-09": "설날 대체", + "2027-03-01": "삼일절", + "2027-05-05": "어린이날", + "2027-05-13": "부처님오신날", + "2027-06-06": "현충일", + "2027-08-15": "광복절", "2027-08-16": "광복절 대체", + "2027-09-14": "추석 연휴", "2027-09-15": "추석", "2027-09-16": "추석 연휴", + "2027-10-03": "개천절", "2027-10-04": "개천절 대체", + "2027-10-09": "한글날", "2027-10-11": "한글날 대체", + "2027-12-25": "성탄절", "2027-12-27": "성탄절 대체", + # 2028 + "2028-01-01": "신정", + "2028-01-26": "설날 연휴", "2028-01-27": "설날", "2028-01-28": "설날 연휴", + "2028-03-01": "삼일절", + "2028-05-02": "부처님오신날", + "2028-05-05": "어린이날", + "2028-06-06": "현충일", + "2028-08-15": "광복절", + "2028-10-02": "추석 연휴", "2028-10-03": "추석·개천절", "2028-10-04": "추석 연휴", + "2028-10-05": "개천절 대체", + "2028-10-09": "한글날", + "2028-12-25": "성탄절", + # 2029 + "2029-01-01": "신정", + "2029-02-12": "설날 연휴", "2029-02-13": "설날", "2029-02-14": "설날 연휴", + "2029-03-01": "삼일절", + "2029-05-05": "어린이날", "2029-05-07": "어린이날 대체", + "2029-05-20": "부처님오신날", "2029-05-21": "부처님오신날 대체", + "2029-06-06": "현충일", + "2029-08-15": "광복절", + "2029-09-21": "추석 연휴", "2029-09-22": "추석", "2029-09-23": "추석 연휴", + "2029-09-24": "추석 대체", + "2029-10-03": "개천절", + "2029-10-09": "한글날", + "2029-12-25": "성탄절", + # 2030 + "2030-01-01": "신정", + "2030-02-02": "설날 연휴", "2030-02-03": "설날", "2030-02-04": "설날 연휴", + "2030-02-05": "설날 대체", + "2030-03-01": "삼일절", + "2030-05-05": "어린이날", "2030-05-06": "어린이날 대체", + "2030-05-09": "부처님오신날", + "2030-06-06": "현충일", + "2030-08-15": "광복절", + "2030-09-11": "추석 연휴", "2030-09-12": "추석", "2030-09-13": "추석 연휴", + "2030-10-03": "개천절", + "2030-10-09": "한글날", + "2030-12-25": "성탄절", +} + + +def holiday_name(iso_date: str) -> str: + """해당 날짜(YYYY-MM-DD)가 공휴일이면 이름을, 아니면 빈 문자열을 반환.""" + return KR_HOLIDAYS.get(iso_date, "") + def norm_str(s: Any, *, lower: bool = False) -> str: out = str(s or "").strip() diff --git a/app/modules/project/templates/project/inbox.html b/app/modules/project/templates/project/inbox.html index 5182ca1..4be6fc9 100644 --- a/app/modules/project/templates/project/inbox.html +++ b/app/modules/project/templates/project/inbox.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} diff --git a/app/modules/project/templates/project/index.html b/app/modules/project/templates/project/index.html index 74c9a79..48ea035 100644 --- a/app/modules/project/templates/project/index.html +++ b/app/modules/project/templates/project/index.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + {% endblock %} diff --git a/app/modules/project/templates/project/project.html b/app/modules/project/templates/project/project.html index 7efca22..48f4b68 100644 --- a/app/modules/project/templates/project/project.html +++ b/app/modules/project/templates/project/project.html @@ -1,7 +1,7 @@ {% extends "erp_base.html" %} {% block head_extra %} - + @@ -126,9 +126,10 @@
{% for cell in week.days %}
+ data-date="{{ cell.date }}" {% if cell.holiday_name %}title="{{ cell.holiday_name }}"{% endif %}> {{ cell.day }} + {% if cell.is_sunday or cell.holiday_name %}pj-red{% elif cell.is_saturday %}pj-blue{% endif %}">{{ cell.day }} + {% if cell.holiday_name %}{{ cell.holiday_name }}{% endif %}
{% endfor %}
diff --git a/app/static/project.css b/app/static/project.css index 48d98e2..5c07af8 100644 --- a/app/static/project.css +++ b/app/static/project.css @@ -390,6 +390,10 @@ .pj-today .pj-day-num.pj-blue { background: #1d4ed8; } .pj-red { color: #c22b10 !important; } .pj-blue { color: #1d4ed8 !important; } +.pj-day-holiday { + display: block; font-size: 10.5px; color: #c22b10; font-weight: 600; + overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; +} /* bar 오버레이 — 날짜 숫자 아래(top)부터 7열 그리드로 겹쳐 그림 */ .pj-week-bars { position: absolute; left: 0; right: 0; top: 34px; bottom: 4px; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); grid-auto-rows: 22px; row-gap: 2px; pointer-events: none; }