Files
pit-router/app/utils/helpers.py

114 lines
2.7 KiB
Python

"""
辅助函数
"""
from datetime import datetime, timedelta
from typing import Optional, Any
import json
def format_datetime(dt: Optional[datetime]) -> Optional[str]:
"""格式化日期时间"""
if not dt:
return None
return dt.isoformat()
def parse_datetime(dt_str: str) -> Optional[datetime]:
"""解析日期时间字符串"""
if not dt_str:
return None
try:
return datetime.fromisoformat(dt_str)
except:
return None
def format_duration(seconds: int) -> str:
"""格式化时长"""
if seconds < 60:
return f"{seconds}s"
elif seconds < 3600:
return f"{seconds // 60}m"
elif seconds < 86400:
return f"{seconds // 3600}h"
else:
return f"{seconds // 86400}d"
def truncate_string(s: str, max_length: int = 100, suffix: str = "...") -> str:
"""截断字符串"""
if len(s) <= max_length:
return s
return s[:max_length - len(suffix)] + suffix
def safe_json_loads(data: str, default: Any = None) -> Any:
"""安全的 JSON 解析"""
try:
return json.loads(data)
except:
return default
def safe_json_dumps(data: Any, default: str = "{}") -> str:
"""安全的 JSON 序列化"""
try:
return json.dumps(data, ensure_ascii=False)
except:
return default
def generate_session_title() -> str:
"""生成默认会话标题"""
return f"Session {datetime.utcnow().strftime('%Y-%m-%d %H:%M')}"
def calculate_timeout(start_time: datetime, timeout_seconds: int) -> bool:
"""检查是否超时"""
if not start_time:
return True
elapsed = (datetime.utcnow() - start_time).total_seconds()
return elapsed > timeout_seconds
def merge_dicts(base: dict, override: dict) -> dict:
"""合并字典"""
result = base.copy()
result.update(override)
return result
def filter_none_values(data: dict) -> dict:
"""过滤字典中的 None 值"""
return {k: v for k, v in data.items() if v is not None}
class PaginationHelper:
"""分页辅助类"""
@staticmethod
def paginate(query, page: int = 1, per_page: int = 20):
"""分页查询"""
if page < 1:
page = 1
if per_page < 1:
per_page = 20
if per_page > 100:
per_page = 100
total = query.count()
items = query.offset((page - 1) * per_page).limit(per_page).all()
pages = (total + per_page - 1) // per_page
return {
'items': items,
'total': total,
'page': page,
'per_page': per_page,
'pages': pages,
'has_next': page < pages,
'has_prev': page > 1,
}