feat: 重构质量管理和设备巡检模块

质量管理: 由平铺记录改为任务制工作流(qc_task/qc_task_item/qc_defect三表)
设备巡检: 由点位+记录改为巡检模板制(eqp_checklist/item/record/detail四表)
前端: Quality.vue 支持任务列表+检验项详情+缺陷记录双Tab
前端: Inspection.vue 支持模板管理+项目维护+巡检记录+明细查看

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-28 16:29:02 +08:00
parent 6ae24cb14d
commit b461f0d2f8
11 changed files with 1645 additions and 749 deletions

View File

@@ -6,9 +6,9 @@ from app.models.downtime import DowntimeRecord, DowntimeCategory
from app.models.equipment import Equipment, EquipmentMaintenance
from app.models.message import MessageLog
from app.models.pdi import PDIRecord
from app.models.quality import QualityRecord
from app.models.quality import QcTask, QcTaskItem, QcDefect
from app.models.energy import EnergyRecord
from app.models.inspection import InspectionLocation, InspectionRecord
from app.models.inspection import EqpChecklist, EqpChecklistItem, EqpInspectionRecord, EqpInspectionDetail
__all__ = [
"User",
@@ -19,7 +19,7 @@ __all__ = [
"Equipment", "EquipmentMaintenance",
"MessageLog",
"PDIRecord",
"QualityRecord",
"QcTask", "QcTaskItem", "QcDefect",
"EnergyRecord",
"InspectionLocation", "InspectionRecord",
"EqpChecklist", "EqpChecklistItem", "EqpInspectionRecord", "EqpInspectionDetail",
]

View File

@@ -1,28 +1,54 @@
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, func
from sqlalchemy import Column, Integer, String, DateTime, Text, Boolean, ForeignKey, func
from app.database import Base
class InspectionLocation(Base):
__tablename__ = "inspection_locations"
class EqpChecklist(Base):
"""设备巡检模板"""
__tablename__ = "eqp_checklist"
id = Column(Integer, primary_key=True, index=True)
code = Column(String(30), unique=True, nullable=False, index=True)
name = Column(String(100), nullable=False)
description = Column(Text)
description = Column(Text, nullable=True)
equipment_code = Column(String(30), nullable=True, index=True)
equipment_name = Column(String(100), nullable=True)
period = Column(String(20), default="daily") # daily/weekly/monthly
is_active = Column(Boolean, default=True)
created_at = Column(DateTime, server_default=func.now())
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
class EqpChecklistItem(Base):
"""巡检模板项目"""
__tablename__ = "eqp_checklist_item"
id = Column(Integer, primary_key=True, index=True)
checklist_id = Column(Integer, ForeignKey("eqp_checklist.id"), nullable=False, index=True)
item_name = Column(String(100), nullable=False)
item_standard = Column(String(200), nullable=True)
sort_order = Column(Integer, default=0)
created_at = Column(DateTime, server_default=func.now())
class InspectionRecord(Base):
__tablename__ = "inspection_records"
class EqpInspectionRecord(Base):
"""巡检记录"""
__tablename__ = "eqp_inspection_record"
id = Column(Integer, primary_key=True, index=True)
location_id = Column(Integer, ForeignKey("inspection_locations.id"), nullable=False)
location_name = Column(String(100))
equipment_code = Column(String(30), index=True)
equipment_name = Column(String(100))
scan_code = Column(String(200))
checklist_id = Column(Integer, ForeignKey("eqp_checklist.id"), nullable=False, index=True)
checklist_name = Column(String(100), nullable=True)
inspector = Column(String(50), nullable=False)
result = Column(String(20), default="normal")
notes = Column(Text)
inspect_time = Column(DateTime, nullable=False)
status = Column(String(20), default="ok") # ok/issue/urgent
overall_result = Column(String(20), nullable=True) # pass/fail
remark = Column(Text, nullable=True)
created_at = Column(DateTime, server_default=func.now())
class EqpInspectionDetail(Base):
"""巡检记录明细"""
__tablename__ = "eqp_inspection_detail"
id = Column(Integer, primary_key=True, index=True)
record_id = Column(Integer, ForeignKey("eqp_inspection_record.id"), nullable=False, index=True)
checklist_item_id = Column(Integer, nullable=True)
item_name = Column(String(100), nullable=False)
actual_value = Column(String(100), nullable=True)
is_ok = Column(Boolean, default=True)
notes = Column(Text, nullable=True)
created_at = Column(DateTime, server_default=func.now())

View File

@@ -2,37 +2,64 @@ from sqlalchemy import Column, Integer, String, Float, DateTime, Text, Boolean,
from app.database import Base
class QualityRecord(Base):
"""质量检验记录"""
__tablename__ = "quality_records"
class QcTask(Base):
"""检验任务"""
__tablename__ = "qc_task"
id = Column(Integer, primary_key=True, index=True)
task_code = Column(String(50), unique=True, nullable=False, index=True)
coil_no = Column(String(30), nullable=True, index=True)
task_type = Column(String(30), nullable=True) # e.g. incoming/process/final
scheme_name = Column(String(100), nullable=True)
status = Column(Integer, default=0) # 0=待检验 1=检验中 2=待审核 3=完成
inspect_user = Column(String(50), nullable=True)
inspect_time = Column(DateTime, nullable=True)
audit_user = Column(String(50), nullable=True)
audit_time = Column(DateTime, nullable=True)
result = Column(String(20), nullable=True) # qualified/unqualified
remark = Column(Text, nullable=True)
del_flag = Column(Integer, default=0)
created_at = Column(DateTime, server_default=func.now())
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())
id = Column(Integer, primary_key=True, index=True)
coil_no = Column(String(30), nullable=False, index=True, comment="卷号")
production_record_id = Column(Integer, ForeignKey("production_records.id"), nullable=True, comment="关联生产实绩")
# 实测规格
thickness_actual = Column(Float, nullable=True, comment="实测厚度 mm")
width_actual = Column(Float, nullable=True, comment="实测宽度 mm")
flatness = Column(Float, nullable=True, comment="平直度 IU")
crown = Column(Float, nullable=True, comment="凸度 μm")
class QcTaskItem(Base):
"""检验项目"""
__tablename__ = "qc_task_item"
id = Column(Integer, primary_key=True, index=True)
task_id = Column(Integer, ForeignKey("qc_task.id"), nullable=False, index=True)
item_name = Column(String(100), nullable=False)
item_type = Column(String(20), nullable=True) # quantitative/qualitative
standard_value = Column(Float, nullable=True)
upper_limit = Column(Float, nullable=True)
lower_limit = Column(Float, nullable=True)
unit = Column(String(20), nullable=True)
inspect_value = Column(String(50), nullable=True)
is_qualified = Column(Integer, nullable=True) # 1=qualified 0=unqualified
judge_result = Column(String(100), nullable=True)
inspect_user = Column(String(50), nullable=True)
inspect_time = Column(DateTime, nullable=True)
created_at = Column(DateTime, server_default=func.now())
# 表面缺陷
surface_defect_type = Column(String(50), nullable=True, comment="表面缺陷类型")
defect_length_m = Column(Float, nullable=True, comment="缺陷长度 m")
defect_position = Column(String(50), nullable=True, comment="缺陷位置")
# 质量模型评分
pi_score = Column(Float, nullable=True, comment="酸洗指数评分 0-100")
surface_score = Column(Float, nullable=True, comment="表面质量评分 0-100")
overall_grade = Column(String(5), nullable=True, comment="综合等级 A1/A2/B1/B2/C")
# 残酸 / 粗糙度
acid_residual = Column(Float, nullable=True, comment="残酸量 g/m²")
roughness_ra = Column(Float, nullable=True, comment="粗糙度 Ra μm")
# 检验信息
inspector = Column(String(50), nullable=True, comment="检验员")
inspect_time = Column(DateTime, nullable=True, comment="检验时间")
is_passed = Column(Boolean, default=True, comment="是否合格")
created_at = Column(DateTime, server_default=func.now())
class QcDefect(Base):
"""钢卷缺陷记录"""
__tablename__ = "qc_defect"
id = Column(Integer, primary_key=True, index=True)
coil_no = Column(String(30), nullable=True, index=True)
production_line = Column(String(50), nullable=True)
position = Column(String(50), nullable=True)
plate_surface = Column(String(20), nullable=True)
defect_code = Column(String(30), nullable=True)
defect_type = Column(String(50), nullable=True, index=True)
defect_rate = Column(Float, nullable=True)
defect_weight = Column(Float, nullable=True)
degree = Column(String(20), nullable=True) # light/normal/serious
judge_level = Column(String(20), nullable=True)
judge_by = Column(String(50), nullable=True)
judge_time = Column(DateTime, nullable=True)
main_mark = Column(Integer, nullable=True)
whole_coil_mark = Column(Integer, nullable=True)
remark = Column(Text, nullable=True)
del_flag = Column(Integer, default=0)
created_at = Column(DateTime, server_default=func.now())
updated_at = Column(DateTime, server_default=func.now(), onupdate=func.now())