# 工单列表 Row 对象序列化问题修复 ## 问题描述 - 点击"进行中"(testStep = 1)或"已完成"(testStep = 5)按钮 - 页面显示"暂无数据" - 数据库中有数据,但前端收不到 ## 根本原因 **DAO 层使用了 `.label()` 后,SQLAlchemy 返回的是 Row 对象,而不是 ORM 模型对象** ### 问题代码 ```python 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 模型 ```python # 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 对象转换为字典** ### 修复代码 ```python # 执行查询并转换为字典列表 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. 重启后端服务(必须!) ```bash # 停止后端服务 # 重新启动 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` 的响应 **正常响应**: ```json { "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_id` 和 `batch_name` 已经在 `test_work_order` 表中**: ```sql -- 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 的工单 **验证**: ```sql SELECT test_step, COUNT(*) FROM test_work_order WHERE order_id IS NULL GROUP BY test_step; ``` **解决方案**: 如果没有 test_step = 1 的工单,手动更新: ```sql 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