add backend source code

This commit is contained in:
2026-02-28 15:06:52 +08:00
parent 1bc330e20c
commit 2c37aa9064
67 changed files with 11654 additions and 0 deletions

View File

@@ -0,0 +1,309 @@
"""
绩效计划管理 API
"""
from typing import Annotated, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.database import get_db
from app.core.security import get_current_active_user, get_current_manager_user
from app.schemas.schemas import (
PerformancePlanCreate, PerformancePlanUpdate, PerformancePlanResponse,
PerformancePlanStats, PlanKpiRelationCreate, PlanKpiRelationUpdate,
ResponseBase
)
from app.services.performance_plan_service import PerformancePlanService
from app.models.models import User, PlanStatus
router = APIRouter(prefix="/plans", tags=["绩效计划管理"])
@router.get("", summary="获取绩效计划列表")
async def get_performance_plans(
plan_level: Optional[str] = Query(None, description="计划层级"),
plan_year: Optional[int] = Query(None, description="计划年度"),
department_id: Optional[int] = Query(None, description="科室 ID"),
status: Optional[str] = Query(None, description="状态"),
page: int = Query(1, ge=1, description="页码"),
page_size: int = Query(20, ge=1, le=100, description="每页数量"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""获取绩效计划列表"""
plans, total = await PerformancePlanService.get_list(
db, plan_level, plan_year, department_id, status, page, page_size
)
# 构建响应数据
plan_list = []
for plan in plans:
plan_dict = {
"id": plan.id,
"plan_name": plan.plan_name,
"plan_code": plan.plan_code,
"plan_level": plan.plan_level,
"plan_year": plan.plan_year,
"plan_month": plan.plan_month,
"status": plan.status,
"department_id": plan.department_id,
"department_name": plan.department.name if plan.department else None,
"staff_id": plan.staff_id,
"staff_name": plan.staff.name if plan.staff else None,
"description": plan.description,
"created_at": plan.created_at,
"updated_at": plan.updated_at
}
plan_list.append(plan_dict)
return {
"code": 200,
"message": "success",
"data": plan_list,
"total": total,
"page": page,
"page_size": page_size
}
@router.get("/tree", summary="获取绩效计划树")
async def get_performance_plan_tree(
plan_year: Optional[int] = Query(None, description="计划年度"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""获取绩效计划树形结构"""
tree = await PerformancePlanService.get_tree(db, plan_year)
return {
"code": 200,
"message": "success",
"data": tree
}
@router.get("/stats", summary="获取绩效计划统计")
async def get_performance_plan_stats(
plan_year: Optional[int] = Query(None, description="计划年度"),
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""获取绩效计划统计信息"""
stats = await PerformancePlanService.get_stats(db, plan_year)
return {
"code": 200,
"message": "success",
"data": stats
}
@router.get("/{plan_id}", summary="获取绩效计划详情")
async def get_performance_plan(
plan_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""获取绩效计划详情"""
plan = await PerformancePlanService.get_by_id(db, plan_id)
if not plan:
raise HTTPException(status_code=404, detail="绩效计划不存在")
# 构建响应数据
kpi_relations = []
for relation in plan.kpi_relations:
kpi_relations.append({
"id": relation.id,
"indicator_id": relation.indicator_id,
"indicator_name": relation.indicator.name if relation.indicator else None,
"indicator_code": relation.indicator.code if relation.indicator else None,
"target_value": relation.target_value,
"target_unit": relation.target_unit,
"weight": relation.weight,
"scoring_method": relation.scoring_method,
"scoring_params": relation.scoring_params,
"remark": relation.remark
})
plan_data = {
"id": plan.id,
"plan_name": plan.plan_name,
"plan_code": plan.plan_code,
"plan_level": plan.plan_level,
"plan_year": plan.plan_year,
"plan_month": plan.plan_month,
"plan_type": plan.plan_type,
"department_id": plan.department_id,
"department_name": plan.department.name if plan.department else None,
"staff_id": plan.staff_id,
"staff_name": plan.staff.name if plan.staff else None,
"parent_plan_id": plan.parent_plan_id,
"description": plan.description,
"strategic_goals": plan.strategic_goals,
"key_initiatives": plan.key_initiatives,
"status": plan.status,
"submitter_id": plan.submitter_id,
"submit_time": plan.submit_time,
"approver_id": plan.approver_id,
"approve_time": plan.approve_time,
"approve_remark": plan.approve_remark,
"version": plan.version,
"is_active": plan.is_active,
"created_at": plan.created_at,
"updated_at": plan.updated_at,
"kpi_relations": kpi_relations
}
return {
"code": 200,
"message": "success",
"data": plan_data
}
@router.post("", summary="创建绩效计划")
async def create_performance_plan(
plan_data: PerformancePlanCreate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""创建绩效计划"""
plan = await PerformancePlanService.create(db, plan_data, current_user.id)
return {
"code": 200,
"message": "创建成功",
"data": {"id": plan.id}
}
@router.put("/{plan_id}", summary="更新绩效计划")
async def update_performance_plan(
plan_id: int,
plan_data: PerformancePlanUpdate,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""更新绩效计划"""
plan = await PerformancePlanService.update(db, plan_id, plan_data)
if not plan:
raise HTTPException(status_code=404, detail="绩效计划不存在")
return {
"code": 200,
"message": "更新成功",
"data": {"id": plan.id}
}
@router.post("/{plan_id}/submit", summary="提交绩效计划")
async def submit_performance_plan(
plan_id: int,
db: AsyncSession = Depends(get_db),
current_user: User = Depends(get_current_active_user)
):
"""提交绩效计划"""
plan = await PerformancePlanService.submit(db, plan_id)
if not plan:
raise HTTPException(status_code=400, detail="无法提交,计划不存在或状态不允许")
return {
"code": 200,
"message": "提交成功"
}
@router.post("/{plan_id}/approve", summary="审批绩效计划")
async def approve_performance_plan(
plan_id: int,
approved: bool = Query(..., description="是否通过"),
remark: Optional[str] = Query(None, description="审批意见"),
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""审批绩效计划(需要管理员或经理权限)"""
plan = await PerformancePlanService.approve(db, plan_id, current_user.id, approved, remark)
if not plan:
raise HTTPException(status_code=400, detail="无法审批,计划不存在或状态不允许")
return {
"code": 200,
"message": "审核通过" if approved else "已驳回"
}
@router.post("/{plan_id}/activate", summary="激活绩效计划")
async def activate_performance_plan(
plan_id: int,
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""激活绩效计划(需要管理员或经理权限)"""
plan = await PerformancePlanService.activate(db, plan_id)
if not plan:
raise HTTPException(status_code=400, detail="无法激活,计划不存在或状态不允许")
return {
"code": 200,
"message": "激活成功"
}
@router.delete("/{plan_id}", summary="删除绩效计划")
async def delete_performance_plan(
plan_id: int,
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""删除绩效计划(需要管理员或经理权限)"""
success = await PerformancePlanService.delete(db, plan_id)
if not success:
raise HTTPException(status_code=404, detail="绩效计划不存在")
return {
"code": 200,
"message": "删除成功"
}
@router.post("/{plan_id}/kpi-relations", summary="添加计划指标关联")
async def add_kpi_relation(
plan_id: int,
kpi_data: PlanKpiRelationCreate,
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""添加计划指标关联(需要管理员或经理权限)"""
relation = await PerformancePlanService.add_kpi_relation(db, plan_id, kpi_data)
if not relation:
raise HTTPException(status_code=404, detail="绩效计划不存在")
return {
"code": 200,
"message": "添加成功",
"data": {"id": relation.id}
}
@router.put("/kpi-relations/{relation_id}", summary="更新计划指标关联")
async def update_kpi_relation(
relation_id: int,
kpi_data: PlanKpiRelationUpdate,
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""更新计划指标关联(需要管理员或经理权限)"""
relation = await PerformancePlanService.update_kpi_relation(db, relation_id, kpi_data.model_dump())
if not relation:
raise HTTPException(status_code=404, detail="指标关联不存在")
return {
"code": 200,
"message": "更新成功",
"data": {"id": relation.id}
}
@router.delete("/kpi-relations/{relation_id}", summary="删除计划指标关联")
async def delete_kpi_relation(
relation_id: int,
db: AsyncSession = Depends(get_db),
current_user: Annotated[User, Depends(get_current_manager_user)] = None
):
"""删除计划指标关联(需要管理员或经理权限)"""
success = await PerformancePlanService.delete_kpi_relation(db, relation_id)
if not success:
raise HTTPException(status_code=404, detail="指标关联不存在")
return {
"code": 200,
"message": "删除成功"
}