refactor(api): 重构数据库访问为SQLAlchemy绑定的session

- 统一移除手动创建的数据库session,统一使用models模块中的db.session
- 修正项目创建接口,增加开始和结束日期的格式验证与处理
- 更新导入项目接口,使用枚举类型校验项目类型并优化异常处理
- 更新统计接口,避免多次查询假期数据,优化日期字符串处理
- 删除回滚前多余的session关闭调用,改为使用db.session.rollback()
- app.py中重构数据库初始化:统一配置SQLAlchemy,动态创建数据库路径和表
- 项目模型新增开始日期和结束日期字段支持
- 添加导入批次历史记录模型支持
- 优化工具函数中日期类型提示,移除无用导入
- 更新requirements.txt依赖版本回退,确保兼容性
- 前端菜单添加导入历史导航入口,实现页面访问路由绑定
This commit is contained in:
2025-09-04 18:12:24 +08:00
parent ef9432f6da
commit 8938ce2708
29 changed files with 3490 additions and 150 deletions

View File

@@ -1,16 +1,16 @@
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import Column, Integer, String, Boolean, DateTime, Text, Date, Time, ForeignKey, Enum
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
from datetime import datetime
import enum
Base = declarative_base()
db = SQLAlchemy()
class ProjectType(enum.Enum):
TRADITIONAL = "traditional" # 传统项目
PSI = "psi" # PSI项目
class Project(Base):
class Project(db.Model):
"""项目表模型"""
__tablename__ = 'projects'
@@ -26,6 +26,8 @@ class Project(Base):
contract_number = Column(String(100)) # 合同号PSI项目必填
description = Column(Text)
start_date = Column(Date, nullable=True) # 项目开始时间
end_date = Column(Date, nullable=True) # 项目结束时间
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
@@ -42,12 +44,14 @@ class Project(Base):
'customer_name': self.customer_name,
'contract_number': self.contract_number,
'description': self.description,
'start_date': self.start_date.isoformat() if self.start_date else None,
'end_date': self.end_date.isoformat() if self.end_date else None,
'is_active': self.is_active,
'created_at': self.created_at.isoformat() if self.created_at else None,
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
class TimeRecord(Base):
class TimeRecord(db.Model):
"""工时记录表模型"""
__tablename__ = 'time_records'
@@ -88,7 +92,7 @@ class TimeRecord(Base):
'updated_at': self.updated_at.isoformat() if self.updated_at else None
}
class Holiday(Base):
class Holiday(db.Model):
"""休息日配置表模型"""
__tablename__ = 'holidays'
@@ -109,7 +113,7 @@ class Holiday(Base):
'created_at': self.created_at.isoformat() if self.created_at else None
}
class CutoffPeriod(Base):
class CutoffPeriod(db.Model):
"""Cut-Off周期表模型"""
__tablename__ = 'cutoff_periods'
@@ -134,4 +138,29 @@ class CutoffPeriod(Base):
'year': self.year,
'month': self.month,
'created_at': self.created_at.isoformat() if self.created_at else None
}
}
class ImportBatch(db.Model):
"""导入批次历史记录模型"""
__tablename__ = 'import_batches'
id = Column(Integer, primary_key=True)
import_date = Column(DateTime, default=datetime.utcnow)
status = Column(String(50), nullable=False)
success_count = Column(Integer, default=0)
failure_count = Column(Integer, default=0)
total_records = Column(Integer, default=0)
source_preview = Column(Text)
failures_log = Column(Text) # 存储失败记录的详细日志
def to_dict(self):
return {
'id': self.id,
'import_date': self.import_date.isoformat(),
'status': self.status,
'success_count': self.success_count,
'failure_count': self.failure_count,
'total_records': self.total_records,
'source_preview': self.source_preview,
'failures_log': self.failures_log
}