后端拆分风险规则生成为解释器、语义分析、本体对齐等子模块, 优化模板执行和流程图生成,完善员工种子数据和导入逻辑,增强 报销单权限策略和草稿持久化,前端新增预算中心视图和趋势图 组件,重构审计页面和风险规则测试对话框交互,完善文档中心 和报销创建页面细节,补充单元测试覆盖。
54 lines
1.4 KiB
Python
54 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, date, datetime
|
|
from zoneinfo import ZoneInfo
|
|
|
|
from app.services.employee_serialization import format_history_datetime as serialize_history_datetime
|
|
|
|
DISPLAY_TIMEZONE = ZoneInfo("Asia/Shanghai")
|
|
|
|
|
|
def normalize_optional_text(value: str | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
text_value = value.strip()
|
|
return text_value or None
|
|
|
|
|
|
def parse_date(value: str | None) -> date | None:
|
|
if not value:
|
|
return None
|
|
return datetime.strptime(value, "%Y-%m-%d").date()
|
|
|
|
|
|
def parse_datetime(value: str | datetime | None) -> datetime | None:
|
|
if value is None:
|
|
return None
|
|
if isinstance(value, datetime):
|
|
return value
|
|
return datetime.strptime(value, "%Y-%m-%d %H:%M")
|
|
|
|
|
|
def format_date(value: date | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
return value.strftime("%Y-%m-%d")
|
|
|
|
|
|
def to_display_datetime(value: datetime) -> datetime:
|
|
if value.tzinfo is None:
|
|
normalized = value.replace(tzinfo=UTC)
|
|
else:
|
|
normalized = value.astimezone(UTC)
|
|
return normalized.astimezone(DISPLAY_TIMEZONE)
|
|
|
|
|
|
def format_datetime(value: datetime | None) -> str | None:
|
|
if value is None:
|
|
return None
|
|
return to_display_datetime(value).strftime("%Y-%m-%d %H:%M")
|
|
|
|
|
|
def format_history_datetime(value: datetime | None) -> str:
|
|
return serialize_history_datetime(value, to_display_datetime=to_display_datetime)
|