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

193 lines
5.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 工单列表 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