- 统一移除手动创建的数据库session,统一使用models模块中的db.session - 修正项目创建接口,增加开始和结束日期的格式验证与处理 - 更新导入项目接口,使用枚举类型校验项目类型并优化异常处理 - 更新统计接口,避免多次查询假期数据,优化日期字符串处理 - 删除回滚前多余的session关闭调用,改为使用db.session.rollback() - app.py中重构数据库初始化:统一配置SQLAlchemy,动态创建数据库路径和表 - 项目模型新增开始日期和结束日期字段支持 - 添加导入批次历史记录模型支持 - 优化工具函数中日期类型提示,移除无用导入 - 更新requirements.txt依赖版本回退,确保兼容性 - 前端菜单添加导入历史导航入口,实现页面访问路由绑定
112 lines
3.8 KiB
Python
112 lines
3.8 KiB
Python
import datetime
|
|
from typing import Optional, Dict, Any, List
|
|
|
|
def is_weekend(date: datetime.date) -> bool:
|
|
"""判断是否为周末"""
|
|
return date.weekday() >= 5 # 周六=5, 周日=6
|
|
|
|
def is_holiday(date: datetime.date, holidays: list = None) -> Dict[str, Any]:
|
|
"""检测指定日期是否为休息日"""
|
|
day_of_week = date.weekday() # 0=周一, 6=周日
|
|
is_weekend_day = day_of_week >= 5 # 周六、周日
|
|
|
|
# 检查是否为配置的节假日
|
|
configured_holiday = None
|
|
if holidays:
|
|
for holiday in holidays:
|
|
if holiday.date == date:
|
|
configured_holiday = holiday
|
|
break
|
|
|
|
is_configured_holiday = configured_holiday is not None
|
|
|
|
return {
|
|
'is_holiday': is_weekend_day or is_configured_holiday,
|
|
'holiday_type': 'weekend' if is_weekend_day else (configured_holiday.holiday_type if configured_holiday else None),
|
|
'holiday_name': configured_holiday.holiday_name if configured_holiday else None,
|
|
'is_working_day': configured_holiday.is_working_day if configured_holiday else False
|
|
}
|
|
|
|
def calculate_hours(start_time: Optional[str], end_time: Optional[str], is_holiday_flag: bool = False) -> str:
|
|
"""工时计算函数"""
|
|
if not start_time or not end_time or start_time == '-' or end_time == '-':
|
|
return '0:00' if is_holiday_flag else '-' # 休息日默认显示0:00而不是-
|
|
|
|
try:
|
|
start = datetime.datetime.strptime(start_time, '%H:%M')
|
|
end = datetime.datetime.strptime(end_time, '%H:%M')
|
|
|
|
# 处理跨日情况
|
|
if end < start:
|
|
end += datetime.timedelta(days=1)
|
|
|
|
diff = end - start
|
|
total_minutes = int(diff.total_seconds() / 60)
|
|
|
|
hours = total_minutes // 60
|
|
minutes = total_minutes % 60
|
|
|
|
return f"{hours}:{minutes:02d}"
|
|
except ValueError:
|
|
return '0:00'
|
|
|
|
def format_hours_to_decimal(hours: str) -> float:
|
|
"""工时格式转换函数:将"2:42"格式转换为小数格式用于计算"""
|
|
if hours == '-' or not hours:
|
|
return 0.0
|
|
|
|
if ':' in hours:
|
|
try:
|
|
parts = hours.split(':')
|
|
h = int(parts[0])
|
|
m = int(parts[1]) if len(parts) > 1 else 0
|
|
return h + (m / 60)
|
|
except ValueError:
|
|
return 0.0
|
|
|
|
try:
|
|
return float(hours)
|
|
except ValueError:
|
|
return 0.0
|
|
|
|
def format_decimal_to_hours(decimal_hours: float) -> str:
|
|
"""将小数工时转换回"HH:MM"格式"""
|
|
hours = int(decimal_hours)
|
|
minutes = int((decimal_hours - hours) * 60)
|
|
return f"{hours}:{minutes:02d}"
|
|
|
|
def calculate_weekly_hours(records: list) -> Dict[str, float]:
|
|
"""工时统计函数(区分工作日和休息日)"""
|
|
workday_hours = sum([
|
|
format_hours_to_decimal(r.get('hours', '0:00'))
|
|
for r in records
|
|
if not r.get('is_holiday', False) and r.get('hours') not in ['-', '0:00', None]
|
|
])
|
|
|
|
holiday_hours = sum([
|
|
format_hours_to_decimal(r.get('hours', '0:00'))
|
|
for r in records
|
|
if r.get('is_holiday', False) and r.get('hours') not in ['-', '0:00', None]
|
|
])
|
|
|
|
return {
|
|
'workday_hours': workday_hours,
|
|
'holiday_hours': holiday_hours,
|
|
'total_hours': workday_hours + holiday_hours
|
|
}
|
|
|
|
def get_week_info(date: datetime.date) -> str:
|
|
"""获取周信息,如"51周/53周" """
|
|
year = date.year
|
|
week_num = date.isocalendar()[1]
|
|
|
|
# 计算该年总共有多少周
|
|
last_day = datetime.date(year, 12, 31)
|
|
total_weeks = last_day.isocalendar()[1]
|
|
|
|
return f"{week_num}周/{total_weeks}周"
|
|
|
|
def get_day_of_week_chinese(date: datetime.date) -> str:
|
|
"""获取中文星期"""
|
|
weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
|
|
return weekdays[date.weekday()] |