Files
KCGL/inventory-backend/app/models/base.py
yueli ffafa635bb feat: 将产品图/说明书备注字段从JSON数组中分离为独立数据库列
- 数据库新增 product_image_remark 和 manual_link_remark 两个TEXT列
- 备注文字不再与上传文件URL混存在 generalImage/generalManual JSON数组中
- 前端输入框改为textarea,绑定独立的备注字段
- 修复 handlePasteLink 忽略field参数的bug
- 新增 isInternalFile 辅助函数,用于区分上传文件与纯文本
- 同步修改 list.vue 和 buyOdoo.vue 两个页面
2026-07-10 10:52:23 +08:00

133 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# app/models/base.py
from app.extensions import db
from pgvector.sqlalchemy import Vector
import json
class MaterialBase(db.Model):
"""
基础信息表模型
对应数据库表: material_base
"""
__tablename__ = 'material_base'
# 1. 基础字段
id = db.Column(db.Integer, primary_key=True)
company_name = db.Column(db.String(255), comment='所属公司')
name = db.Column(db.String(255), nullable=False, index=True, comment='名称') # ★ 模糊搜索/精确定位高频列
common_name = db.Column(db.String(255), comment='俗名')
category = db.Column(db.String(100), index=True, comment='类别') # ★ 分类统计/过滤高频列
material_type = db.Column(db.String(100), index=True, comment='类型') # ★ 类型分组/过滤高频列
spec_model = db.Column(db.String(255), index=True, comment='规格型号') # ★ 模糊搜索/精确匹配高频列
unit = db.Column(db.String(50), comment='计量单位')
# 可见等级
visibility_level = db.Column(db.Integer, default=0, comment='信息可见等级')
# 链接与图片 (现在存储 JSON 字符串)
manual_link = db.Column(db.Text, comment='通用说明书')
product_image = db.Column(db.Text, comment='通用产品图')
# 备注字段(纯文本,与文件 URL 分离存储)
product_image_remark = db.Column(db.Text, default='', comment='产品图备注')
manual_link_remark = db.Column(db.Text, default='', comment='说明书备注')
# 启用状态
is_enabled = db.Column(db.Boolean, default=True, comment='是否启用')
# 强制质检标记(采购入库时必须上传检测报告)
is_inspection_required = db.Column(db.Boolean, default=False, comment='是否强制要求质检')
# CLIP 视觉向量(用于以图搜图)
img_embedding = db.Column(Vector(512), nullable=True)
# ============================================================
# 关联关系区域
# ============================================================
# 1. 关联采购库存 (StockBuy)
stock_buys = db.relationship('StockBuy', back_populates='base', lazy='dynamic')
# 2. 关联半成品库存 (StockSemi)
stock_semis = db.relationship('StockSemi', back_populates='base', lazy='dynamic')
# 3. 关联成品库存 (StockProduct)
stock_products = db.relationship('StockProduct', back_populates='base', lazy='dynamic')
# 4. 关联服务库存 (StockService)
stock_services = db.relationship('StockService', back_populates='base', lazy='dynamic')
# 5. 关联预警设置 (MaterialWarningSetting)
warning_settings = db.relationship('MaterialWarningSetting', back_populates='material', lazy='dynamic', cascade='all, delete-orphan')
def to_dict(self):
"""
序列化方法
"""
# 辅助解析函数:将数据库存储的 JSON 字符串转为 List
def parse_list(json_str):
if not json_str:
return []
try:
# 兼容旧数据:如果不是 JSON 格式(比如是单个 URL),则包装成 list
if not json_str.startswith('['):
return [json_str]
return json.loads(json_str)
except:
return []
return {
'id': self.id,
'companyName': self.company_name,
'name': self.name,
'commonName': self.common_name,
'category': self.category,
'type': self.material_type,
'spec': self.spec_model,
'unit': self.unit,
'visibilityLevel': self.visibility_level,
'generalManual': parse_list(self.manual_link),
'generalImage': parse_list(self.product_image),
'productImageRemark': self.product_image_remark or '',
'manualLinkRemark': self.manual_link_remark or '',
# 【核心修改】:直接返回布尔值,不再转成 1 或 0
'isEnabled': bool(self.is_enabled),
# 强制质检标记
'isInspectionRequired': bool(self.is_inspection_required),
}
class MaterialWarningSetting(db.Model):
"""
物料预警设置表模型
对应数据库表: material_warning_settings
"""
__tablename__ = 'material_warning_settings'
id = db.Column(db.Integer, primary_key=True)
base_id = db.Column(db.Integer, db.ForeignKey('material_base.id'), nullable=False, comment='物料基础信息ID')
is_enabled = db.Column(db.Boolean, default=False, comment='是否启用预警')
yellow_threshold = db.Column(db.Numeric(10, 2), nullable=True, comment='黄色预警阈值')
red_threshold = db.Column(db.Numeric(10, 2), nullable=True, comment='红色预警阈值')
yellow_emails = db.Column(db.String(500), nullable=True, comment='黄色预警通知邮箱')
red_emails = db.Column(db.String(500), nullable=True, comment='红色预警通知邮箱')
is_ordered = db.Column(db.Boolean, default=False, comment='是否已处理采购')
last_notified_at = db.Column(db.DateTime, nullable=True, comment='上次邮件通知时间')
# 关联关系
material = db.relationship('MaterialBase', back_populates='warning_settings')
def to_dict(self):
return {
'id': self.id,
'baseId': self.base_id,
'isEnabled': bool(self.is_enabled),
'yellowThreshold': float(self.yellow_threshold) if self.yellow_threshold is not None else None,
'redThreshold': float(self.red_threshold) if self.red_threshold is not None else None,
'yellowEmails': self.yellow_emails or '',
'redEmails': self.red_emails or '',
'isOrdered': bool(self.is_ordered),
'lastNotifiedAt': self.last_notified_at.strftime('%Y-%m-%d %H:%M:%S') if self.last_notified_at else None
}