8.4 KiB
工单批次分组功能实现说明
需求背景
样品生成工单后,需要有一个"分组"标识来识别同一批次生成的工单,方便管理和查看。
解决方案
添加"工单批次"字段,用于标识同一批次生成的工单:
batch_id: 批次ID(使用时间戳生成唯一ID)batch_name: 批次名称(用户填写的"工单名称"或自动生成)
实现内容
⚠️ 重要:数据类型修复
问题: 时间戳(毫秒级)超出 INTEGER 范围,导致 "Out of range value" 错误
解决: 将 batch_id 字段改为 BIGINT 类型
1. 数据库修改
文件: add_workorder_batch_field.sql 或 fix_batch_id_bigint.sql
-- 重命名字段并修改类型为 BIGINT
ALTER TABLE test_work_order
CHANGE COLUMN test_order_id batch_id BIGINT NULL COMMENT '工单批次ID(用于分组标识)';
-- 添加批次名称字段
ALTER TABLE test_work_order
ADD COLUMN batch_name VARCHAR(100) NULL COMMENT '工单批次名称' AFTER batch_id;
如果已经执行过重命名,只需修改类型:
-- 紧急修复:只修改字段类型
ALTER TABLE test_work_order
MODIFY COLUMN batch_id BIGINT NULL COMMENT '工单批次ID(用于分组标识)';
执行步骤:
# 方式1:完整迁移(如果还没执行过)
mysql -u root -p your_database < add_workorder_batch_field.sql
# 方式2:紧急修复(如果已经重命名但类型错误)
mysql -u root -p your_database < fix_batch_id_bigint.sql
2. 后端修改
2.1 DO 模型
文件: test_work_order_do.py
from sqlalchemy import BigInteger # 导入 BigInteger
batch_id = Column(BigInteger, nullable=True, comment='工单批次ID(用于分组标识)')
batch_name = Column(String(100), nullable=True, comment='工单批次名称')
注意: 必须使用 BigInteger 而不是 Integer,因为时间戳(毫秒级)会超出 INTEGER 范围。
2.2 VO 模型
文件: test_work_order_vo.py
batch_id: Optional[int] = Field(default=None, description='工单批次ID')
batch_name: Optional[str] = Field(default=None, description='工单批次名称')
2.3 样品生成工单逻辑
文件: warehouse_sample_service.py
生成批次ID和名称:
# 生成批次ID(使用时间戳)
batch_id = int(datetime.now().timestamp() * 1000) # 毫秒级时间戳
batch_name = request_model.work_order_name or f'批次-{datetime.now().strftime("%Y%m%d%H%M%S")}'
创建工单时关联批次:
work_order = TestWorkOrder(
name=work_order_name,
batch_id=batch_id, # 关联批次ID
batch_name=batch_name, # 批次名称
...
)
2.4 工单查询 DAO
文件: test_work_order_dao.py
- 添加
batch_id和batch_name到查询字段 - 将查询条件从
test_order_id改为batch_id
3. 前端修改
3.1 工单列表页面
文件: test_work_order/index.vue
添加"工单分组"列:
<el-table-column label="工单分组" align="center" prop="batchName" width="150" />
修改查询参数:
queryParams: {
batchId: null, // 从 testOrderId 改为 batchId
...
}
修改验证逻辑:
// 验证工单是否属于同一批次
const batchIds = [...new Set(this.selectedWorkOrders.map(wo => wo.batchId))];
if (batchIds.length > 1) {
this.$modal.msgError("选中的工单必须属于同一批次");
return;
}
使用说明
样品生成工单
- 进入样品管理页面
- 选择样品,点击"生成工单"
- 填写"工单名称"(可选):
- 如果填写,批次名称 = 工单名称
- 如果不填,批次名称 =
批次-20260108215713(自动生成)
- 提交后,所有工单都会有相同的批次ID和批次名称
工单列表查看
- 进入工单列表页面
- 可以看到"工单分组"列,显示批次名称
- 同一批次的工单会显示相同的分组名称
- 可以通过分组名称识别和筛选工单
工单生成订单
- 选择工单时,系统会验证是否属于同一批次
- 只能选择同一批次的工单生成订单
- 如果选择了不同批次的工单,会提示错误
数据示例
数据库数据
id | batch_id | batch_name | name | test_eut_id
----|-----------------|-----------------|----------------|------------
721 | 1704726433000 | 测试批次A | 测试批次A-SN001 | 119
722 | 1704726433000 | 测试批次A | 测试批次A-SN002 | 120
723 | 1704726433000 | 测试批次A | 测试批次A-SN003 | 121
724 | 1704726500000 | 批次-20260108 | SN004-入射 | 122
前端显示
| 序号 | 工单分组 | 产品SN | 测试类别 | 测试项 |
|---|---|---|---|---|
| 1 | 测试批次A | SN001 | 入射 | 测试1 |
| 2 | 测试批次A | SN002 | 入射 | 测试1 |
| 3 | 测试批次A | SN003 | 入射 | 测试1 |
| 4 | 批次-20260108 | SN004 | 入射 | 测试1 |
优势
- 清晰的分组标识:通过批次名称快速识别同一批次的工单
- 灵活的命名:用户可以自定义批次名称,也可以使用自动生成的名称
- 独立的批次管理:批次ID独立于订单,工单可以独立存在
- 便于筛选:可以通过批次名称筛选和查看工单
与订单的关系
- batch_id: 工单批次ID(样品生成工单时设置,标识同一批次)
- order_id: 关联订单ID(从工单生成订单后设置,标识已汇总到订单)
工单状态:
- 新建工单:
batch_id = 时间戳,order_id = NULL - 已汇总工单:
batch_id = 时间戳,order_id = 订单ID
相关文件
add_workorder_batch_field.sql- 数据库迁移脚本 ✅test_work_order_do.py- 工单DO模型 ✅test_work_order_vo.py- 工单VO模型 ✅warehouse_sample_service.py- 样品服务 ✅test_work_order_dao.py- 工单DAO ✅test_work_order/index.vue- 工单列表前端 ✅
完成时间
2026-01-08
最终修复:DAO 层字段序列化问题
问题描述
数据库中有工单数据(batch_id 和 batch_name 都有值),但工单列表页面不显示任何数据。
根本原因
DAO 层的 select() 语句中,部分字段(如 batch_id、batch_name 等)没有使用 .label() 显式指定列名。虽然 SQLAlchemy 会自动推断列名,但在序列化为 JSON 时可能导致字段名不一致。
解决方案
文件: test_work_order_dao.py
在 get_test_work_order_list 方法中,为所有 TestWorkOrder 的字段添加 .label():
query = (
select(
TestWorkOrder.id.label('id'),
TestWorkOrder.batch_id.label('batch_id'),
TestWorkOrder.batch_name.label('batch_name'),
TestWorkOrder.test_eut_id.label('test_eut_id'),
# ... 其他字段都添加 .label()
)
# ... 其他查询逻辑
)
为什么需要 .label()
- 一致性: 确保所有字段都有明确的列名
- 序列化:
SqlalchemyUtil.serialize_result依赖Row._asdict()获取列名 - camelCase 转换:
CamelCaseUtil.snake_to_camel需要正确的 snake_case 列名
数据流程
DAO (Row对象)
→ PageUtil (调用 CamelCaseUtil.transform_result)
→ SqlalchemyUtil (Row._asdict() 转字典)
→ CamelCaseUtil (snake_case → camelCase)
→ Controller (返回 JSON)
→ 前端 (显示数据)
当前状态
✅ 已完成 - 工单批次分组功能已全部实现并修复
完成清单
- 数据库字段类型修复(BIGINT)
- DO 模型更新(BigInteger)
- VO 模型添加字段
- 业务逻辑生成批次ID和名称
- DAO 查询返回批次字段
- 前端显示工单分组列
- DAO 层字段 label 修复 - 确保所有字段正确序列化
- 工单列表正常显示批次信息
验证步骤
- ✅ 重启后端服务
- ✅ 清除浏览器缓存(Ctrl + Shift + R)
- ✅ 检查浏览器开发者工具 Network 标签
- ✅ 确认 API 返回正确的 camelCase 字段(batchId, batchName)
- ✅ 工单列表显示"工单分组"列
- ✅ 批次名称正确显示
相关文档
工单列表显示修复完成.md- 详细的修复说明工单列表不显示问题诊断.md- 诊断步骤QUICKFIX_批次ID类型错误.md- BIGINT 类型修复修复订单DAO中的test_order_id引用.md- 订单DAO修复
最终完成时间
2026-01-08 23:30