ETest-Vue-FastAPI/工单列表Row对象序列化问题修复.md

5.0 KiB
Raw Permalink Blame History

工单列表 Row 对象序列化问题修复

问题描述

  • 点击"进行中"testStep = 1或"已完成"testStep = 5按钮
  • 页面显示"暂无数据"
  • 数据库中有数据,但前端收不到

根本原因

DAO 层使用了 .label()SQLAlchemy 返回的是 Row 对象,而不是 ORM 模型对象

问题代码

query = (
    select(
        TestWorkOrder.id.label('id'),
        TestWorkOrder.batch_id.label('batch_id'),
        # ... 其他字段
    )
    # ...
)
result = await PageUtil.paginate(db, query, page_num, page_size, is_page)
return result  # ❌ 返回的是 Row 对象列表

为什么会出问题?

  1. 使用 .label()SQLAlchemy 返回 Row 对象而不是 ORM 模型
  2. Pydantic 无法直接序列化 Row 对象
  3. FastAPI 返回数据时序列化失败,导致前端收到空数据或错误

Row 对象 vs ORM 模型

# ORM 模型(可以直接序列化)
result = await db.execute(select(TestWorkOrder))
rows = result.scalars().all()  # 返回 TestWorkOrder 对象列表

# Row 对象(需要转换为字典)
result = await db.execute(select(TestWorkOrder.id.label('id'), ...))
rows = result.all()  # 返回 Row 对象列表,需要转换

解决方案

将 Row 对象转换为字典

修复代码

# 执行查询并转换为字典列表
result = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)

# 如果是分页查询,需要转换 rows 为字典
if is_page and hasattr(result, 'rows'):
    result.rows = [dict(row._mapping) for row in result.rows]
elif not is_page:
    result = [dict(row._mapping) for row in result]

return result

为什么这样修复?

  1. row._mapping: SQLAlchemy 2.0 提供的属性,返回 Row 对象的字段映射
  2. dict(row._mapping): 将 Row 对象转换为普通字典
  3. Pydantic 可以序列化字典: FastAPI 可以正常返回数据

修复文件

文件: ruoyi-fastapi-backend/module_admin/system/dao/test_work_order_dao.py

方法: get_test_work_order_list

验证步骤

1. 重启后端服务(必须!)

# 停止后端服务
# 重新启动
cd ruoyi-fastapi-backend
python main.py

2. 清除浏览器缓存

Windows: Ctrl + Shift + R

3. 测试工单列表

  1. 点击"全部工单" - 应该能看到所有工单
  2. 点击"待领取" - 应该能看到 test_step = 0 的工单
  3. 点击"进行中" - 应该能看到 test_step = 1 的工单
  4. 点击"已完成" - 应该能看到 test_step = 5 的工单

4. 检查浏览器开发者工具

  1. F12
  2. Network 标签
  3. 点击"进行中"按钮
  4. 查看 /system/test_work_order/list 的响应

正常响应:

{
  "code": 200,
  "data": {
    "rows": [
      {
        "id": 821,
        "batchId": 1767886248798,
        "batchName": "批次-20260108233048",
        "name": "SN0001-出库测试PCBA",
        "testEutName": "SN0001",
        "creatorName": "管理员",
        "testCategoryName": "PCBA测试",
        "testItemName": "出库测试",
        "testStep": 1,
        "testStatus": 0
      }
    ],
    "total": 10
  }
}

为什么不需要批次表?

batch_idbatch_name 已经在 test_work_order 表中

-- test_work_order 表结构
CREATE TABLE test_work_order (
    id INT PRIMARY KEY,
    batch_id BIGINT,           -- 批次ID时间戳
    batch_name VARCHAR(100),   -- 批次名称
    name VARCHAR(200),         -- 工单名称
    test_step INT,             -- 测试步骤
    order_id INT,              -- 关联的订单ID
    -- ... 其他字段
);

批次的作用:

  • batch_id: 用于标识同一批次生成的工单(相同的时间戳)
  • batch_name: 用于显示批次名称(如"批次-20260108233048"
  • 不需要单独的批次表,因为批次信息直接存储在工单表中

其他可能的问题

问题 1: 数据库中没有对应 test_step 的工单

验证:

SELECT test_step, COUNT(*) 
FROM test_work_order 
WHERE order_id IS NULL 
GROUP BY test_step;

解决方案: 如果没有 test_step = 1 的工单,手动更新:

UPDATE test_work_order 
SET test_step = 1 
WHERE order_id IS NULL 
  AND test_step = 0
LIMIT 5;

问题 2: 后端服务没有重启

症状: 修改代码后,问题仍然存在

解决方案: 必须重启后端服务

问题 3: 浏览器缓存

症状: 后端已修复,但前端仍显示旧数据

解决方案: 清除浏览器缓存Ctrl + Shift + R

预期结果

修复后:

  • "全部工单"显示所有未关联订单的工单
  • "待领取"显示 test_step = 0 的工单
  • "进行中"显示 test_step = 1 的工单
  • "一审中"显示 test_step = 2 的工单
  • "二审中"显示 test_step = 3 的工单
  • "三审中"显示 test_step = 4 的工单
  • "已完成"显示 test_step = 5 的工单
  • 工单分组batchName正确显示

完成时间

2026-01-09 00:45