ETest-Vue-FastAPI/样品状态同步问题修复说明.md

7.8 KiB
Raw Permalink Blame History

样品状态同步问题修复说明

问题描述

删除数据库中的工单数据后,重新生成工单时提示"已有工单",无法创建新工单。

根本原因

与 Redis 无关问题在于样品表warehouse_sample的状态字段与工单表不同步

  1. 样品生成工单时,样品状态从 '0'(待测试)更新为 '1'(测试中)
  2. 删除工单时,只删除了工单数据,没有重置样品状态
  3. 再次生成工单时,系统检查到样品状态不是 '0',认为"已有工单",拒绝创建

相关代码

样品状态检查逻辑

文件: warehouse_sample_service.py 第 162-171 行

# 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 行

# 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 脚本重置样品状态:

mysql -u root -p your_database < reset_sample_status.sql

SQL 内容:

-- 重置所有样品状态为"待测试"
UPDATE warehouse_sample
SET status = '0',
    update_time = NOW()
WHERE status != '0';

适用场景:

  • 开发/测试环境
  • 需要快速清理数据重新测试
  • 确认所有工单都已删除

方案 2使用 force 参数(临时方案)

前端在生成工单时传递 force: true 参数:

// 前端代码
const response = await generateWorkOrderFromSamples({
  sampleIds: selectedSampleIds,
  testFlowId: testFlowId,
  workOrderName: workOrderName,
  force: true  // 强制生成,跳过状态检查
});

适用场景:

  • 临时需要重新生成工单
  • 不想修改数据库数据
  • 明确知道样品没有关联的工单

方案 3添加级联删除逻辑长期方案

修改工单删除逻辑,删除工单时自动重置样品状态。

3.1 修改工单删除 Service

文件: test_work_order_service.py

@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

@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' 已完成 样品测试完成

数据一致性检查

检查样品状态与工单的一致性

-- 查找状态为"测试中"但没有工单的样品
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;

修复不一致的数据

-- 重置没有工单的"测试中"样品
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. 执行重置脚本

mysql -u root -p your_database < reset_sample_status.sql

2. 检查样品状态

SELECT status, COUNT(*) FROM warehouse_sample GROUP BY status;

预期结果:所有样品状态应该是 '0'(待测试)

3. 重新生成工单

  1. 进入样品管理页面
  2. 选择样品
  3. 点击"生成工单"
  4. 应该能够成功创建工单

4. 验证样品状态更新

-- 查看刚才生成工单的样品状态
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 语句:

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