企业级软件研发团队绩效考核系统开发(持续更新 Day 7)

0 阅读6分钟

作者:呱牛

发布日期:2026年3月30日

标签:FastAPI、绩效考核

🔥 今日亮点

2026年3月30日 - 任务明细文件上传功能开发

  • 实现双文件上传功能:前端页面新增独立的任务明细上传按钮
  • 创建*_pa_task_assignment_score模块:完整的Model、Schema、CRUD三层架构
  • 实现Excel解析入库功能:解析《团队任务派单明细》并存入数据库
  • 修复CRUD类初始化问题:正确使用泛型类型参数和关键字参数
  • 修复模块导入路径错误:统一使用app.core.base_crud导入路径
  • 实现动态CRUD类加载:使用importlib动态导入CRUD类
  • 完善事务管理机制:确保数据正确提交到数据库

📋 文章目录


🎯 任务明细文件上传功能开发

1.1 功能需求

在现有绩效考核指标明细上传功能的基础上,新增任务明细文件上传功能:

  • 前端页面新增独立的文件上传按钮
  • 后端单独开发解析方法,不影响现有功能
  • 数据存入*_pa_task_assignment_score
  • 关联考核期次和数据时点字段

1.2 实现步骤

步骤1:前端页面修改

index.vue中新增任务明细上传按钮:

<!-- 绩效明细上传 -->
<el-col :span="12">
  <el-form-item label="绩效明细:">
    <SingleFileUpload
      v-model="formData.file_path"
      :file-type="['xlsx', 'xls']"
      accept=".xlsx,.xls"
      tip="选择Excel文件(《绩效考核指标明细》)"
    />
  </el-form-item>
</el-col>

<!-- 任务明细上传(新增) -->
<el-col :span="12">
  <el-form-item label="任务明细:">
    <SingleFileUpload
      v-model="formData.task_file_path"
      :file-type="['xlsx', 'xls']"
      accept=".xlsx,.xls"
      tip="选择Excel文件(《团队任务派单明细》)"
    />
  </el-form-item>
</el-col>

步骤2:后端Schema扩展

schema.py中新增字段:

class *PaExcelUploadRecordCreateSchema(BaseModel):
    """绩效考核期次文件上传记录新增模型"""
    assessment_period: str = Field(..., description='考核期次(格式:YYYYMM)')
    data_date: date = Field(..., description='数据时点(格式:YYYY-MM-DD)')
    file_path: str | None = Field(default=None, description='绩效考核指标明细文件路径')
    task_file_path: str | None = Field(default=None, description='团队任务派单明细文件路径')  # 新增
    task_file_name: str | None = Field(default=None, description='团队任务派单明细文件名称')  # 新增

步骤3:创建数据模型

创建*_pa_task_assignment_score/model.py

# -*- coding: utf-8 -*-

from datetime import date
from sqlalchemy import Date, String, Float
from sqlalchemy.orm import Mapped, mapped_column

from app.core.base_model import ModelMixin, UserMixin


class *PaTaskAssignmentScoreModel(ModelMixin, UserMixin):
    """
    团队任务派单得分表
    """
    __tablename__: str = 'yurdmc_pa_task_assignment_score'
    __table_args__: dict[str, str] = {'comment': '团队任务派单得分'}
    __loader_options__: list[str] = ["created_by", "updated_by"]

    staff_no: Mapped[str | None] = mapped_column(String(50), nullable=True, comment='员工工号')
...
    assessment_period: Mapped[str | None] = mapped_column(String(6), nullable=True, comment='考核期次(格式:YYYYMM)')
    data_date: Mapped[date | None] = mapped_column(Date, nullable=True, comment='数据时点(格式:YYYY-MM-DD)')

步骤4:创建CRUD类

创建*_pa_task_assignment_score/crud.py

# -*- coding: utf-8 -*-

from typing import Sequence

class *PaTaskAssignmentScoreCRUD(CRUDBase[*PaTaskAssignmentScoreModel, *PaTaskAssignmentScoreCreateSchema, *PaTaskAssignmentScoreUpdateSchema]):
    """团队任务派单得分数据层"""

    def __init__(self, auth: AuthSchema) -> None:
        """
        初始化CRUD数据层
        
        参数:
        - auth (AuthSchema): 认证信息模型
        """
        super().__init__(model=*PaTaskAssignmentScoreModel, auth=auth)


📊 完整流程

2.1 任务明细文件上传流程图

开始
  ↓
用户选择任务明细Excel文件
  ↓
前端上传文件到服务器
  ↓
后端接收文件并保存路径
  ↓
调用_parse_task_assignment_file方法
  ↓
读取Excel文件内容
  ↓
检查必要列是否存在
  ↓
动态导入CRUD类
  ↓
遍历Excel行数据
  ↓
  ↓  构建数据字典
  ↓  开启嵌套事务
  ↓  调用CRUD.create方法
  ↓  提交事务
  ↓
记录插入和跳过数量
  ↓
返回解析结果
  ↓
结束

2.2 数据流转图

┌─────────────────────────────────────────────────────────────┐
  前端:文件上传                                          
  ┌───────────────────────────────────────────────────────┐ 
    SingleFileUpload组件                                
    - 选择Excel文件                                    
    - 上传到服务器                                     
    - 返回文件路径                                     
  └───────────────────────────────────────────────────────┘ 
└─────────────────────────────────────────────────────────────┘
                                
                                
┌─────────────────────────────────────────────────────────────┐
  后端:文件解析                                          
  ┌───────────────────────────────────────────────────────┐ 
    _parse_task_assignment_file方法                     
    - pandas读取Excel                                  
    - 检查列名                                         
    - 构建数据字典                                     
  └───────────────────────────────────────────────────────┘ 
└─────────────────────────────────────────────────────────────┘
                                
                                
┌─────────────────────────────────────────────────────────────┐
  数据库:数据入库                                        
  ┌───────────────────────────────────────────────────────┐ 
    *_pa_task_assignment_score表                   
    - staff_no: 员工工号                               
    - real_name: 员工姓名                              
    - team_name: 归属团队                              
    - task_name: 任务名称                              
    - task_score: 明细得分                             
    - assessment_period: 考核期次                       
    - data_date: 数据时点                              
  └───────────────────────────────────────────────────────┘ 
└─────────────────────────────────────────────────────────────┘


🚀 技术要点

3.1 CRUD模式最佳实践

# 1. 正确的泛型类型参数
class MyCRUD(CRUDBase[MyModel, MyCreateSchema, MyUpdateSchema]):

# 2. 使用关键字参数初始化
def __init__(self, auth: AuthSchema) -> None:
    super().__init__(model=MyModel, auth=auth)

# 3. 正确的导入路径
from app.core.base_crud import CRUDBase

3.2 动态模块导入

import importlib

# 动态导入模块
module_path = "app.plugin.module_gencode.table_name.crud"
module = importlib.import_module(module_path)

# 动态获取类
class_name = "TableNameCRUD"
crud_class = getattr(module, class_name)

# 实例化对象
crud_instance = crud_class(auth)

优势:

  • 支持动态加载不同表的CRUD类
  • 避免硬编码依赖
  • 提高代码的灵活性和可扩展性

3.3 事务管理

# 嵌套事务(推荐)
async with auth.db.begin_nested():
    await crud.create(data=data)

# 手动事务管理
try:
    async with auth.db.begin():
        await crud.create(data=data)
except Exception as e:
    await auth.db.rollback()
    raise

注意事项:

  • 使用begin_nested()创建嵌套事务
  • 事务会在上下文管理器退出时自动提交或回滚
  • 避免在循环中频繁创建事务

3.4 Excel解析

import pandas as pd

# 读取Excel文件
df = pd.read_excel(file_path)

# 检查必要列
required_columns = ['列1', '列2', '列3']
missing_columns = [col for col in required_columns if col not in df.columns]
if missing_columns:
    raise ValueError(f"缺少必要列: {missing_columns}")

# 遍历行数据
for _, row in df.iterrows():
    value = row['列名']
    if pd.isna(value):
        value = None


📈 待实现功能

4.1 任务明细功能扩展

  • 任务明细得分汇总计算
  • 任务明细与绩效考核结果关联
  • 任务明细数据去重处理

4.2 功能完善

  • 数据验证和异常处理
  • 单元测试和集成测试
  • 用户界面优化
  • 导出报表功能

📝 今日总结

5.1 完成功能

  1. 任务明细文件上传功能完整实现
  2. *_pa_task_assignment_score模块创建
  3. CRUD类正确实现(泛型类型参数、关键字参数)
  4. 动态CRUD类加载功能实现
  5. Excel解析入库功能实现
  6. 事务管理机制完善
  7. 多个技术问题修复

5.2 技术收获

  1. 掌握CRUD模式的正确实现方式
  2. 学会使用泛型类型参数
  3. 理解动态模块导入的原理和应用
  4. 掌握事务管理的最佳实践
  5. 提高Excel解析和数据处理能力
  6. 理解模块化开发的重要性

5.3 踩坑记录

问题原因解决方案
TypeError: unexpected keyword argument参数顺序错误使用关键字参数
'function' object is not subscriptable缺少泛型类型参数添加类型参数
ModuleNotFoundError导入路径错误修正导入路径
AttributeError: no attribute 'tablename'模型继承错误继承正确的基类
缺少必要列列名不匹配修正列名

5.4 下一步计划

  1. 实现任务明细得分汇总计算