# 样品状态同步问题修复说明 ## 问题描述 删除数据库中的工单数据后,重新生成工单时提示"已有工单",无法创建新工单。 ## 根本原因 **与 Redis 无关**,问题在于样品表(warehouse_sample)的状态字段与工单表不同步: 1. 样品生成工单时,样品状态从 `'0'`(待测试)更新为 `'1'`(测试中) 2. 删除工单时,只删除了工单数据,**没有重置样品状态** 3. 再次生成工单时,系统检查到样品状态不是 `'0'`,认为"已有工单",拒绝创建 ## 相关代码 ### 样品状态检查逻辑 **文件**: `warehouse_sample_service.py` 第 162-171 行 ```python # 4.2 验证样品状态(只允许待测试状态的样品,除非force=True) if not request_model.force and sample.status != '0': failed_samples.append(FailedSampleInfo( sampleId=sample_id, sampleSn=sample.sample_sn, reason='已有工单' )) failed_count += 1 continue ``` ### 样品状态更新逻辑 **文件**: `warehouse_sample_service.py` 第 237-243 行 ```python # 4.8 如果该样品至少创建了一个工单,更新样品状态为"测试中" if sample_work_order_count > 0: # 只有当样品状态为"待测试"时才更新为"测试中" if sample.status == '0': sample.status = '1' # 测试中 sample.update_time = datetime.now() await db.flush() ``` ## 解决方案 ### 方案 1:重置样品状态(快速修复)✅ 推荐 执行 SQL 脚本重置样品状态: ```bash mysql -u root -p your_database < reset_sample_status.sql ``` **SQL 内容**: ```sql -- 重置所有样品状态为"待测试" UPDATE warehouse_sample SET status = '0', update_time = NOW() WHERE status != '0'; ``` **适用场景**: - 开发/测试环境 - 需要快速清理数据重新测试 - 确认所有工单都已删除 ### 方案 2:使用 force 参数(临时方案) 前端在生成工单时传递 `force: true` 参数: ```javascript // 前端代码 const response = await generateWorkOrderFromSamples({ sampleIds: selectedSampleIds, testFlowId: testFlowId, workOrderName: workOrderName, force: true // 强制生成,跳过状态检查 }); ``` **适用场景**: - 临时需要重新生成工单 - 不想修改数据库数据 - 明确知道样品没有关联的工单 ### 方案 3:添加级联删除逻辑(长期方案) 修改工单删除逻辑,删除工单时自动重置样品状态。 #### 3.1 修改工单删除 Service **文件**: `test_work_order_service.py` ```python @classmethod async def delete_test_work_order_services(cls, query_db: AsyncSession, page_object: DeleteTest_work_orderModel): """ 删除测试工单信息service """ if page_object.ids: id_list = page_object.ids.split(',') try: # 1. 查询要删除的工单,获取关联的test_eut_id work_order_ids = [int(id) for id in id_list] work_orders = await Test_work_orderDao.get_work_orders_by_ids(query_db, work_order_ids) # 2. 收集所有test_eut_id test_eut_ids = list(set([wo.test_eut_id for wo in work_orders if wo.test_eut_id])) # 3. 删除工单 for id in id_list: await Test_work_orderDao.delete_test_work_order_dao(query_db, Test_work_orderModel(id=id)) # 4. 检查每个test_eut是否还有其他工单 from module_admin.system.entity.do.test_eut_do import TestEut from module_admin.dao.warehouse_sample_dao import WarehouseSampleDao from sqlalchemy import select, func for test_eut_id in test_eut_ids: # 查询该test_eut是否还有其他工单 remaining_count = (await query_db.execute( select(func.count(TestWorkOrder.id)) .where(TestWorkOrder.test_eut_id == test_eut_id) )).scalar() # 如果没有其他工单了,重置对应样品的状态 if remaining_count == 0: # 通过test_eut的SN查找样品 test_eut = await query_db.get(TestEut, test_eut_id) if test_eut: sample = await WarehouseSampleDao.get_sample_by_sn(query_db, test_eut.sn) if sample: sample.status = '0' # 重置为待测试 sample.update_time = datetime.now() await query_db.commit() return CrudResponseModel(is_success=True, message='删除成功') except Exception as e: await query_db.rollback() raise e else: raise ServiceException(message='传入工单ID为空') ``` #### 3.2 添加 DAO 方法 **文件**: `warehouse_sample_dao.py` ```python @classmethod async def get_sample_by_sn(cls, db: AsyncSession, sample_sn: str): """ 根据样品SN获取样品信息 :param db: orm对象 :param sample_sn: 样品SN :return: 样品对象 """ result = await db.execute( select(WarehouseSample) .where(WarehouseSample.sample_sn == sample_sn) ) return result.scalars().first() ``` **适用场景**: - 生产环境 - 需要保证数据一致性 - 长期维护的系统 ## 样品状态说明 | 状态值 | 状态名称 | 说明 | |--------|----------|------| | '0' | 待测试 | 样品已入库,未生成工单 | | '1' | 测试中 | 样品已生成工单,正在测试 | | '2' | 已完成 | 样品测试完成 | ## 数据一致性检查 ### 检查样品状态与工单的一致性 ```sql -- 查找状态为"测试中"但没有工单的样品 SELECT s.sample_id, s.sample_sn, s.status, COUNT(wo.id) AS work_order_count FROM warehouse_sample s LEFT JOIN test_eut te ON s.sample_sn = te.sn LEFT JOIN test_work_order wo ON te.id = wo.test_eut_id WHERE s.status = '1' -- 测试中 GROUP BY s.sample_id, s.sample_sn, s.status HAVING work_order_count = 0; ``` ### 修复不一致的数据 ```sql -- 重置没有工单的"测试中"样品 UPDATE warehouse_sample s LEFT JOIN test_eut te ON s.sample_sn = te.sn LEFT JOIN test_work_order wo ON te.id = wo.test_eut_id SET s.status = '0', s.update_time = NOW() WHERE s.status = '1' AND wo.id IS NULL; ``` ## 验证步骤 ### 1. 执行重置脚本 ```bash mysql -u root -p your_database < reset_sample_status.sql ``` ### 2. 检查样品状态 ```sql SELECT status, COUNT(*) FROM warehouse_sample GROUP BY status; ``` 预期结果:所有样品状态应该是 `'0'`(待测试) ### 3. 重新生成工单 1. 进入样品管理页面 2. 选择样品 3. 点击"生成工单" 4. 应该能够成功创建工单 ### 4. 验证样品状态更新 ```sql -- 查看刚才生成工单的样品状态 SELECT sample_id, sample_sn, status FROM warehouse_sample WHERE sample_id IN (选中的样品ID); ``` 预期结果:状态应该变为 `'1'`(测试中) ## 常见问题 ### Q1: 为什么不是 Redis 缓存问题? **A**: 代码中没有使用 Redis 缓存样品状态或工单数据。状态检查直接查询数据库。 ### Q2: 重启 Redis 有用吗? **A**: 无用。问题在于数据库中的样品状态字段,与 Redis 无关。 ### Q3: 如果只想重置特定样品的状态怎么办? **A**: 使用带条件的 UPDATE 语句: ```sql UPDATE warehouse_sample SET status = '0', update_time = NOW() WHERE sample_id IN (1, 2, 3); -- 指定样品ID ``` ### Q4: 删除工单后为什么不自动重置样品状态? **A**: 当前代码没有实现级联更新逻辑。建议采用方案 3 添加级联删除逻辑。 ## 相关文件 - `warehouse_sample_service.py` - 样品服务(状态检查和更新) - `test_work_order_service.py` - 工单服务(删除逻辑) - `warehouse_sample_dao.py` - 样品DAO - `reset_sample_status.sql` - 重置样品状态脚本 ✅ ## 完成时间 2026-01-08 23:45