save code

This commit is contained in:
Your Name
2026-01-27 17:30:17 +08:00
parent a416e2091f
commit 884b9f47a2
17 changed files with 910 additions and 44 deletions
Binary file not shown.
Binary file not shown.
+4 -3
View File
@@ -3,11 +3,12 @@ from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
import os
import bcrypt
from app.config import settings
from app.database.database import get_db
from app.models.user import User
from app.schemas.auth import Token
from app.common.utils import verify_password, create_access_token
from app.common.utils import create_access_token
router = APIRouter(prefix="/auth", tags=["认证"])
@@ -17,8 +18,8 @@ def login(form_data: OAuth2PasswordRequestForm = Depends(), db: Session = Depend
"""用户登录"""
user = db.query(User).filter(User.username == form_data.username).first()
# 密码验证:比较用户存储的密码
if not user or form_data.password != user.password:
# 密码验证:使用bcrypt直接验证密码
if not user or not bcrypt.checkpw(form_data.password.encode('utf-8'), user.password.encode('utf-8')):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
+36 -3
View File
@@ -1,4 +1,4 @@
from typing import List
from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session
from app.database.database import get_db
@@ -16,11 +16,32 @@ router = APIRouter(prefix="/projects", tags=["项目管理"])
def get_projects(
skip: int = 0,
limit: int = 100,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
min_budget: Optional[int] = None,
max_budget: Optional[int] = None,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""获取项目列表"""
projects = db.query(Project).offset(skip).limit(limit).all()
projects = db.query(Project)
# 按开始日期筛选
if start_date:
projects = projects.filter(Project.start_date >= start_date)
# 按结束日期筛选
if end_date:
projects = projects.filter(Project.end_date <= end_date)
# 按预算范围筛选
if min_budget is not None:
projects = projects.filter(Project.budget >= min_budget)
if max_budget is not None:
projects = projects.filter(Project.budget <= max_budget)
projects = projects.offset(skip).limit(limit).all()
return projects
@@ -38,12 +59,24 @@ def create_project(
)
# 创建新项目
db_project = Project(
project_code=project.project_code,
name=project.name,
project_type=project.project_type,
description=project.description,
department=project.department,
contract_amount=project.contract_amount,
project_manager=project.project_manager,
client_company=project.client_company,
client_contact=project.client_contact,
contract_date=project.contract_date,
budget=project.budget,
start_date=project.start_date,
end_date=project.end_date,
planned_end_date=project.planned_end_date,
actual_end_date=project.actual_end_date,
progress=project.progress,
actual_received_amount=project.actual_received_amount,
payment_completion_rate=project.payment_completion_rate,
payment_terms=project.payment_terms,
status=project.status,
created_by=current_user.id
)
+23 -11
View File
@@ -1,4 +1,4 @@
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Float
from sqlalchemy.sql import func
from app.database.database import Base
@@ -8,13 +8,25 @@ class Project(Base):
__tablename__ = "projects"
id = Column(Integer, primary_key=True, index=True)
name = Column(String(100), nullable=False)
description = Column(Text)
created_by = Column(Integer, ForeignKey("users.id"), nullable=False)
department = Column(String(50), nullable=False)
budget = Column(Integer)
start_date = Column(DateTime(timezone=True))
end_date = Column(DateTime(timezone=True))
status = Column(String(20), default="pending")
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
project_code = Column(String(50), unique=True, index=True) # 项目编号
name = Column(String(100), nullable=False) # 项目名称
project_type = Column(String(50)) # 工程类别
description = Column(Text) # 项目描述
created_by = Column(Integer, ForeignKey("users.id"), nullable=False) # 创建人
department = Column(String(50), nullable=False) # 所属部门
contract_amount = Column(Float) # 合同金额(万元)
project_manager = Column(String(100)) # 项目负责人
client_company = Column(String(100)) # 建设单位
client_contact = Column(String(100)) # 建设单位联系人
contract_date = Column(DateTime(timezone=True)) # 合同签订日期
budget = Column(Integer) # 预算
start_date = Column(DateTime(timezone=True)) # 开始日期
planned_end_date = Column(DateTime(timezone=True)) # 计划结束日期
actual_end_date = Column(DateTime(timezone=True)) # 实际结束日期
progress = Column(Float, default=0.0) # 累计进度(%
actual_received_amount = Column(Float, default=0.0) # 实际收款金额(万元)
payment_completion_rate = Column(Float, default=0.0) # 回款完成率(%
payment_terms = Column(Text) # 付款方式
status = Column(String(20), default="pending") # 状态
created_at = Column(DateTime(timezone=True), server_default=func.now()) # 创建时间
updated_at = Column(DateTime(timezone=True), onupdate=func.now()) # 更新时间
+32 -8
View File
@@ -5,13 +5,25 @@ from typing import Optional
class ProjectBase(BaseModel):
"""项目基础模型"""
name: str
description: Optional[str] = None
department: str
budget: Optional[int] = None
start_date: Optional[datetime] = None
end_date: Optional[datetime] = None
status: Optional[str] = "pending"
project_code: Optional[str] = None # 项目编号
name: str # 项目名称
project_type: Optional[str] = None # 工程类别
description: Optional[str] = None # 项目描述
department: str # 所属部门
contract_amount: Optional[float] = None # 合同金额(万元)
project_manager: Optional[str] = None # 项目负责人
client_company: Optional[str] = None # 建设单位
client_contact: Optional[str] = None # 建设单位联系人
contract_date: Optional[datetime] = None # 合同签订日期
budget: Optional[int] = None # 预算
start_date: Optional[datetime] = None # 开始日期
planned_end_date: Optional[datetime] = None # 计划结束日期
actual_end_date: Optional[datetime] = None # 实际结束日期
progress: Optional[float] = 0.0 # 累计进度(%
actual_received_amount: Optional[float] = 0.0 # 实际收款金额(万元)
payment_completion_rate: Optional[float] = 0.0 # 回款完成率(%
payment_terms: Optional[str] = None # 付款方式
status: Optional[str] = "pending" # 状态
class ProjectCreate(ProjectBase):
@@ -21,12 +33,24 @@ class ProjectCreate(ProjectBase):
class ProjectUpdate(BaseModel):
"""更新项目模型"""
project_code: Optional[str] = None
name: Optional[str] = None
project_type: Optional[str] = None
description: Optional[str] = None
department: Optional[str] = None
contract_amount: Optional[float] = None
project_manager: Optional[str] = None
client_company: Optional[str] = None
client_contact: Optional[str] = None
contract_date: Optional[datetime] = None
budget: Optional[int] = None
start_date: Optional[datetime] = None
end_date: Optional[datetime] = None
planned_end_date: Optional[datetime] = None
actual_end_date: Optional[datetime] = None
progress: Optional[float] = None
actual_received_amount: Optional[float] = None
payment_completion_rate: Optional[float] = None
payment_terms: Optional[str] = None
status: Optional[str] = None
+59
View File
@@ -0,0 +1,59 @@
from app.database.database import SessionLocal
from app.models import User
import bcrypt
def create_initial_users():
"""创建初始用户"""
db = SessionLocal()
try:
# 检查是否已有用户
existing_users = db.query(User).count()
if existing_users > 0:
print(f"Database already has {existing_users} users. Skipping initialization.")
return
# 创建初始用户
password = "123456"
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
users = [
User(
username="admin",
password=hashed_password,
department="IT",
role="admin"
),
User(
username="marketing",
password=hashed_password,
department="Marketing",
role="marketing"
),
User(
username="other",
password=hashed_password,
department="Other",
role="other"
)
]
for user in users:
db.add(user)
db.commit()
print("Initial users created successfully!")
print("Username: admin, Password: 123456")
print("Username: marketing, Password: 123456")
print("Username: other, Password: 123456")
except Exception as e:
db.rollback()
print(f"Error creating initial users: {e}")
finally:
db.close()
if __name__ == "__main__":
create_initial_users()
+89
View File
@@ -0,0 +1,89 @@
import pandas as pd
from datetime import datetime
from app.database.database import SessionLocal
from app.models import Project, User
def import_projects_from_excel():
"""从Excel文件导入项目数据"""
db = SessionLocal()
try:
# 读取Excel文件
excel_path = "/home/xsl/code/xsl_node/docs/example.xls"
print(f"Reading Excel file: {excel_path}")
# 读取所有工作表
xls = pd.ExcelFile(excel_path)
print(f"Excel file has sheets: {xls.sheet_names}")
# 读取第一个工作表
df = pd.read_excel(xls, sheet_name=0)
print(f"Read {len(df)} rows from Excel")
# 获取marketing用户ID
marketing_user = db.query(User).filter(User.username == "marketing").first()
if not marketing_user:
print("Marketing user not found. Exiting.")
return
# 准备导入的项目数据
projects_to_import = []
skipped_rows = 0
for index, row in df.iterrows():
try:
# 创建项目对象
project = Project(
project_code=str(row.get('项目编号', f'PROJ{index+1}')),
name=str(row.get('项目名称', f'项目{index+1}')),
project_type=str(row.get('工程类别', '')),
description=str(row.get('项目描述', '')),
department=str(row.get('所属部门', '未知部门')),
contract_amount=float(row.get('合同金额(万元)', 0)) if pd.notna(row.get('合同金额(万元)')) else 0,
project_manager=str(row.get('项目负责人', '')),
client_company=str(row.get('建设单位', '')),
client_contact=str(row.get('建设单位联系人', '')),
contract_date=pd.to_datetime(row.get('合同签订日期')).date() if pd.notna(row.get('合同签订日期')) else None,
start_date=pd.to_datetime(row.get('开始日期')).date() if pd.notna(row.get('开始日期')) else None,
planned_end_date=pd.to_datetime(row.get('计划结束日期')).date() if pd.notna(row.get('计划结束日期')) else None,
actual_end_date=pd.to_datetime(row.get('实际结束日期')).date() if pd.notna(row.get('实际结束日期')) else None,
progress=float(row.get('累计进度(%', 0)) if pd.notna(row.get('累计进度(%')) else 0,
actual_received_amount=float(row.get('实际收款金额(万元)', 0)) if pd.notna(row.get('实际收款金额(万元)')) else 0,
payment_completion_rate=float(row.get('回款完成率(%', 0)) if pd.notna(row.get('回款完成率(%')) else 0,
payment_terms=str(row.get('付款方式', '')),
status=str(row.get('状态', 'pending')),
created_by=marketing_user.id
)
projects_to_import.append(project)
# 每100条记录打印一次进度
if (index + 1) % 100 == 0:
print(f"Processed {index + 1} rows...")
except Exception as e:
print(f"Error processing row {index + 1}: {e}")
skipped_rows += 1
continue
# 批量导入数据
if projects_to_import:
print(f"Importing {len(projects_to_import)} projects to database...")
db.add_all(projects_to_import)
db.commit()
print(f"Successfully imported {len(projects_to_import)} projects!")
print(f"Skipped {skipped_rows} rows due to errors")
else:
print("No projects to import")
except Exception as e:
db.rollback()
print(f"Error importing projects: {e}")
import traceback
traceback.print_exc()
finally:
db.close()
if __name__ == "__main__":
import_projects_from_excel()
+13
View File
@@ -0,0 +1,13 @@
from app.database.database import engine, Base
from app.models import User, Project, ProjectHistory
def init_db():
"""初始化数据库"""
print("Creating database tables...")
Base.metadata.create_all(bind=engine)
print("Database tables created successfully!")
if __name__ == "__main__":
init_db()
+168
View File
@@ -0,0 +1,168 @@
from app.database.database import engine, Base
from app.models import User, Project
from app.database.database import SessionLocal
import bcrypt
from datetime import datetime
def init_db():
"""初始化数据库"""
print("Creating database tables...")
Base.metadata.create_all(bind=engine)
print("Database tables created successfully!")
def create_initial_users():
"""创建初始用户"""
db = SessionLocal()
try:
# 检查是否已有用户
existing_users = db.query(User).count()
if existing_users > 0:
print(f"Database already has {existing_users} users. Skipping initialization.")
return
# 创建初始用户
password = "123456"
hashed_password = bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
users = [
User(
username="admin",
password=hashed_password,
department="IT",
role="admin"
),
User(
username="marketing",
password=hashed_password,
department="Marketing",
role="marketing"
),
User(
username="other",
password=hashed_password,
department="Other",
role="other"
)
]
for user in users:
db.add(user)
db.commit()
print("Initial users created successfully!")
print("Username: admin, Password: 123456")
print("Username: marketing, Password: 123456")
print("Username: other, Password: 123456")
except Exception as e:
db.rollback()
print(f"Error creating initial users: {e}")
finally:
db.close()
def create_sample_projects():
"""创建示例项目数据"""
db = SessionLocal()
try:
# 检查是否已有项目
existing_projects = db.query(Project).count()
if existing_projects > 0:
print(f"Database already has {existing_projects} projects. Skipping initialization.")
return
# 获取marketing用户ID
marketing_user = db.query(User).filter(User.username == "marketing").first()
if not marketing_user:
print("Marketing user not found. Skipping project creation.")
return
# 创建示例项目
projects = [
Project(
project_code="chdj2023178",
name="台江县井洞塘抽水变设备调试",
project_type="分部用户工程",
description="台江县井洞塘抽水变设备调试项目",
department="台江项目部",
contract_amount=0.60,
project_manager="杨如云559714",
client_company="张小平",
client_contact="张小平15908557788",
contract_date=datetime(2023, 6, 8),
start_date=datetime(2023, 6, 8),
planned_end_date=datetime(2023, 6, 13),
actual_end_date=datetime(2023, 6, 13),
progress=1.00,
actual_received_amount=0.60,
payment_completion_rate=1.00,
payment_terms="合同签生效后,5个工作日内,甲方向乙方支付全部工程款,工程竣工后,乙方应出具试验报告及试验资质给甲方,乙方拨付每笔工程款时应向甲方提供等额的增值税发票。",
status="completed",
created_by=marketing_user.id
),
Project(
project_code="chdj2023179",
name="凯里市开怀街道配电工程",
project_type="配电工程",
description="凯里市开怀街道配电工程建设",
department="凯里项目部",
contract_amount=120.50,
project_manager="王小明559715",
client_company="凯里市供电局",
client_contact="李经理13985556677",
contract_date=datetime(2023, 5, 15),
start_date=datetime(2023, 5, 20),
planned_end_date=datetime(2023, 8, 30),
actual_end_date=datetime(2023, 9, 5),
progress=1.00,
actual_received_amount=120.50,
payment_completion_rate=1.00,
payment_terms="合同签订后支付30%预付款,工程进度达到50%时支付30%进度款,工程竣工验收后支付35%工程款,预留5%质保金一年后支付。",
status="completed",
created_by=marketing_user.id
),
Project(
project_code="chdj2023180",
name="雷山县西江镇线路改造工程",
project_type="线路工程",
description="雷山县西江镇10kV线路改造工程",
department="雷山项目部",
contract_amount=85.20,
project_manager="陈小红559716",
client_company="雷山县供电局",
client_contact="张主任13885554433",
contract_date=datetime(2023, 7, 10),
start_date=datetime(2023, 7, 15),
planned_end_date=datetime(2023, 10, 20),
actual_end_date=None,
progress=0.75,
actual_received_amount=63.90,
payment_completion_rate=0.75,
payment_terms="按工程进度付款,每月25日上报进度,次月10日前支付进度款的80%,竣工验收后支付至95%,质保金5%一年后支付。",
status="in_progress",
created_by=marketing_user.id
)
]
for project in projects:
db.add(project)
db.commit()
print("Sample projects created successfully!")
print(f"Created {len(projects)} sample projects.")
except Exception as e:
db.rollback()
print(f"Error creating sample projects: {e}")
finally:
db.close()
if __name__ == "__main__":
init_db()
create_initial_users()
create_sample_projects()