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

268 lines
7.8 KiB
Markdown
Raw Permalink Normal View History

# 样品状态同步问题修复说明
## 问题描述
删除数据库中的工单数据后,重新生成工单时提示"已有工单",无法创建新工单。
## 根本原因
**与 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