225 lines
4.8 KiB
Python
225 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
포맷터 모듈
|
|
데이터 포맷팅 함수를 제공합니다.
|
|
"""
|
|
|
|
import json
|
|
from datetime import datetime, date, time
|
|
from typing import Any, Dict
|
|
|
|
from core.logger import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
def format_team_confirmations(confirmations: str) -> str:
|
|
"""
|
|
팀 확인 상태 포맷팅
|
|
|
|
Args:
|
|
confirmations: JSON 문자열
|
|
|
|
Returns:
|
|
포맷된 문자열 (예: "A✓ B✓ C✗ D✗")
|
|
"""
|
|
try:
|
|
data = json.loads(confirmations)
|
|
except (json.JSONDecodeError, TypeError):
|
|
data = {}
|
|
|
|
result = []
|
|
for team in ["A팀", "B팀", "C팀", "D팀"]:
|
|
initial = team[0]
|
|
if data.get(team, False):
|
|
result.append(f"{initial}✓")
|
|
else:
|
|
result.append(f"{initial}✗")
|
|
|
|
return " ".join(result)
|
|
|
|
|
|
def format_bool(value: bool, true_text: str = "예", false_text: str = "아니오") -> str:
|
|
"""
|
|
불린 값 포맷팅
|
|
|
|
Args:
|
|
value: 불린 값
|
|
true_text: True일 때 텍스트
|
|
false_text: False일 때 텍스트
|
|
|
|
Returns:
|
|
포맷된 문자열
|
|
"""
|
|
return true_text if value else false_text
|
|
|
|
|
|
def format_bool_check(value: bool) -> str:
|
|
"""
|
|
불린 값을 체크 표시로 포맷팅
|
|
|
|
Args:
|
|
value: 불린 값
|
|
|
|
Returns:
|
|
✓ 또는 빈 문자열
|
|
"""
|
|
return "✓" if value else ""
|
|
|
|
|
|
def format_cleaning_type(cleaning_type: str) -> str:
|
|
"""
|
|
청소 유형 포맷팅
|
|
|
|
Args:
|
|
cleaning_type: 청소 유형
|
|
|
|
Returns:
|
|
아이콘과 함께 포맷된 문자열
|
|
"""
|
|
if cleaning_type == "중청소":
|
|
return "□ 중청소"
|
|
elif cleaning_type == "대청소":
|
|
return "○ 대청소"
|
|
else:
|
|
return ""
|
|
|
|
|
|
def format_file_size(size_bytes: int) -> str:
|
|
"""
|
|
파일 크기 포맷팅
|
|
|
|
Args:
|
|
size_bytes: 바이트 크기
|
|
|
|
Returns:
|
|
포맷된 문자열 (예: "1.5 MB")
|
|
"""
|
|
if size_bytes < 1024:
|
|
return f"{size_bytes} B"
|
|
elif size_bytes < 1024 * 1024:
|
|
return f"{size_bytes / 1024:.1f} KB"
|
|
elif size_bytes < 1024 * 1024 * 1024:
|
|
return f"{size_bytes / 1024 / 1024:.1f} MB"
|
|
else:
|
|
return f"{size_bytes / 1024 / 1024 / 1024:.1f} GB"
|
|
|
|
|
|
def format_duration(seconds: int) -> str:
|
|
"""
|
|
시간 길이 포맷팅
|
|
|
|
Args:
|
|
seconds: 초
|
|
|
|
Returns:
|
|
포맷된 문자열 (예: "1시간 30분")
|
|
"""
|
|
if seconds < 60:
|
|
return f"{seconds}초"
|
|
elif seconds < 3600:
|
|
minutes = seconds // 60
|
|
secs = seconds % 60
|
|
if secs > 0:
|
|
return f"{minutes}분 {secs}초"
|
|
return f"{minutes}분"
|
|
else:
|
|
hours = seconds // 3600
|
|
minutes = (seconds % 3600) // 60
|
|
if minutes > 0:
|
|
return f"{hours}시간 {minutes}분"
|
|
return f"{hours}시간"
|
|
|
|
|
|
def format_relative_date(d: date) -> str:
|
|
"""
|
|
상대적 날짜 포맷팅
|
|
|
|
Args:
|
|
d: date 객체
|
|
|
|
Returns:
|
|
상대적 날짜 문자열 (예: "오늘", "어제", "2일 전")
|
|
"""
|
|
if d is None:
|
|
return ""
|
|
|
|
today = date.today()
|
|
delta = (today - d).days
|
|
|
|
if delta == 0:
|
|
return "오늘"
|
|
elif delta == 1:
|
|
return "어제"
|
|
elif delta == 2:
|
|
return "그저께"
|
|
elif delta < 7:
|
|
return f"{delta}일 전"
|
|
elif delta < 30:
|
|
weeks = delta // 7
|
|
return f"{weeks}주 전"
|
|
elif delta < 365:
|
|
months = delta // 30
|
|
return f"{months}개월 전"
|
|
else:
|
|
years = delta // 365
|
|
return f"{years}년 전"
|
|
|
|
|
|
def format_train_display(
|
|
train_number: str,
|
|
cleaning_type: str = "없음",
|
|
has_work: bool = False
|
|
) -> str:
|
|
"""
|
|
편성 표시 포맷팅
|
|
|
|
Args:
|
|
train_number: 편성번호
|
|
cleaning_type: 청소유형
|
|
has_work: 작업여부
|
|
|
|
Returns:
|
|
포맷된 문자열
|
|
"""
|
|
result = train_number
|
|
|
|
if cleaning_type == "중청소":
|
|
result = f"[{result}]" # 대괄호 = 파란 네모
|
|
elif cleaning_type == "대청소":
|
|
result = f"({result})" # 소괄호 = 빨간 동그라미
|
|
|
|
if has_work:
|
|
result = f"{result}!" # 느낌표 = 작업 있음
|
|
|
|
return result
|
|
|
|
|
|
def record_to_dict(record: Any, exclude_fields: list = None) -> Dict[str, Any]:
|
|
"""
|
|
레코드를 딕셔너리로 변환
|
|
|
|
Args:
|
|
record: 레코드 객체
|
|
exclude_fields: 제외할 필드
|
|
|
|
Returns:
|
|
딕셔너리
|
|
"""
|
|
exclude = exclude_fields or []
|
|
|
|
if hasattr(record, 'to_dict'):
|
|
data = record.to_dict()
|
|
elif hasattr(record, '__dict__'):
|
|
data = record.__dict__.copy()
|
|
else:
|
|
return {}
|
|
|
|
# 제외 필드 제거
|
|
for field in exclude:
|
|
data.pop(field, None)
|
|
|
|
return data
|
|
|
|
|