diff --git a/inventory-backend/app/models/base.py b/inventory-backend/app/models/base.py
index 20ea4fb..21e5210 100644
--- a/inventory-backend/app/models/base.py
+++ b/inventory-backend/app/models/base.py
@@ -12,6 +12,9 @@ class MaterialBase(db.Model):
# 1. 基础字段
id = db.Column(db.Integer, primary_key=True)
+ # [修改] 所属公司,去除了 default='IRIS'
+ company_name = db.Column(db.String(255), comment='所属公司')
+
name = db.Column(db.String(255), nullable=False, comment='名称')
common_name = db.Column(db.String(255), comment='俗名')
category = db.Column(db.String(100), comment='类别')
@@ -42,8 +45,7 @@ class MaterialBase(db.Model):
# 3. 关联成品库存 (StockProduct)
stock_products = db.relationship('StockProduct', back_populates='base', lazy='dynamic')
- # 4. 关联服务库存 (StockService) - [新增]
- # 假设您的服务库存模型类名为 StockService,且有 base_id 外键
+ # 4. 关联服务库存 (StockService)
stock_services = db.relationship('StockService', back_populates='base', lazy='dynamic')
def to_dict(self):
@@ -65,6 +67,7 @@ class MaterialBase(db.Model):
return {
'id': self.id,
+ 'companyName': self.company_name,
'name': self.name,
'commonName': self.common_name,
'category': self.category,
@@ -72,7 +75,6 @@ class MaterialBase(db.Model):
'spec': self.spec_model,
'unit': self.unit,
'visibilityLevel': self.visibility_level,
- # 修改:解析为列表返回
'generalManual': parse_list(self.manual_link),
'generalImage': parse_list(self.product_image),
'isEnabled': 1 if self.is_enabled else 0,
diff --git a/inventory-backend/app/services/inbound/base_service.py b/inventory-backend/app/services/inbound/base_service.py
index 12538b5..eecc8e2 100644
--- a/inventory-backend/app/services/inbound/base_service.py
+++ b/inventory-backend/app/services/inbound/base_service.py
@@ -4,7 +4,6 @@ from app.extensions import db
from app.models.base import MaterialBase
from app.models.inbound.buy import StockBuy
from app.models.inbound.semi import StockSemi
-# 假设您有 StockProduct 和 StockService 的模型定义
# from app.models.inbound.product import StockProduct
# from app.models.inbound.service import StockService
from sqlalchemy import or_
@@ -33,7 +32,9 @@ class MaterialBaseService:
or_(
MaterialBase.name.ilike(f'%{keyword}%'),
MaterialBase.common_name.ilike(f'%{keyword}%'),
- MaterialBase.spec_model.ilike(f'%{keyword}%')
+ MaterialBase.spec_model.ilike(f'%{keyword}%'),
+ # 支持搜索公司名
+ MaterialBase.company_name.ilike(f'%{keyword}%')
)
).limit(20)
@@ -41,6 +42,7 @@ class MaterialBaseService:
for item in query.all():
results.append({
'id': item.id,
+ 'companyName': item.company_name,
'name': item.name,
'commonName': item.common_name,
'spec': item.spec_model,
@@ -58,29 +60,21 @@ class MaterialBaseService:
def _get_stock_counts(stock_query):
"""
辅助函数:安全计算库存列表的总数量
- 修复逻辑:优先查找 'stock_quantity' (Buy/Semi/Product表中实际使用的字段)
"""
total_inv = 0
total_avail = 0
- # 如果 stock_query 是动态加载的查询对象 (AppenderQuery),需要迭代它
- # 如果是列表,直接迭代
try:
items = list(stock_query) # 触发查询
except:
items = []
for x in items:
- # 1. 获取库存数
- # 【修复点】根据你提供的 Service 代码,Buy/Semi/Product 均使用 stock_quantity
- # Service 使用 actual_quantity,这里做兼容查找
+ # 1. 获取库存数 (兼容不同字段名)
q = getattr(x, 'stock_quantity', getattr(x, 'actual_quantity', getattr(x, 'quantity', 0)))
-
# 2. 获取可用数
- # 这里的字段名通常都是 available_quantity
a = getattr(x, 'available_quantity', q)
- # 累加 (转 float 防止 None 或 Decimal 计算报错)
try:
total_inv += float(q if q is not None else 0)
total_avail += float(a if a is not None else 0)
@@ -93,13 +87,12 @@ class MaterialBaseService:
def get_list(page, limit, filters=None):
"""
获取基础信息列表 (带分页和筛选)
- 并聚合库存总数和可用总数
"""
try:
query = MaterialBase.query
if filters:
- # 1. 关键词模糊搜索 (名称 或 俗名 或 规格型号)
+ # 1. 关键词模糊搜索
if filters.get('keyword'):
kw = f"%{filters['keyword']}%"
query = query.filter(or_(
@@ -109,6 +102,10 @@ class MaterialBaseService:
))
# 2. 精确筛选
+ # 公司筛选
+ if filters.get('company'):
+ query = query.filter_by(company_name=filters['company'])
+
if filters.get('category'):
query = query.filter_by(category=filters['category'])
@@ -116,7 +113,6 @@ class MaterialBaseService:
query = query.filter_by(material_type=filters['type'])
if filters.get('isEnabled') is not None:
- # 前端传 1/0,转为 Boolean
is_active = bool(int(filters['isEnabled']))
query = query.filter_by(is_enabled=is_active)
@@ -125,25 +121,14 @@ class MaterialBaseService:
items_list = []
for item in pagination.items:
- # 获取基础字典
item_dict = item.to_dict()
- # [调用修复后的辅助函数]
-
- # 1. 采购库存 (StockBuy)
+ # 聚合库存
buy_inv, buy_avail = MaterialBaseService._get_stock_counts(item.stock_buys)
-
- # 2. 半成品库存 (StockSemi)
semi_inv, semi_avail = MaterialBaseService._get_stock_counts(item.stock_semis)
-
- # 3. 成品库存 (StockProduct)
prod_inv, prod_avail = MaterialBaseService._get_stock_counts(item.stock_products)
-
- # 4. 服务库存 (StockService)
- # 使用 getattr 防止关联不存在时报错
serv_inv, serv_avail = MaterialBaseService._get_stock_counts(getattr(item, 'stock_services', []))
- # 合并总数
item_dict['inventoryCount'] = buy_inv + semi_inv + prod_inv + serv_inv
item_dict['availableCount'] = buy_avail + semi_avail + prod_avail + serv_avail
@@ -159,37 +144,45 @@ class MaterialBaseService:
@staticmethod
def get_distinct_options():
"""
- 获取所有已存在的类别和类型 (去重)
- 用于前端下拉筛选
+ 获取所有已存在的类别、类型、公司 (去重且排序)
"""
try:
- # 查询所有不为空的类别并去重
+ # 1. 类别 (获取后在内存或前端做层级处理,这里先按字母序返回扁平列表)
categories = db.session.query(MaterialBase.category) \
.filter(MaterialBase.category != None, MaterialBase.category != '') \
.distinct().all()
- # 查询所有不为空的类型并去重
+ # 对类别进行排序
+ sorted_categories = sorted([c[0] for c in categories])
+
+ # 2. 类型
types = db.session.query(MaterialBase.material_type) \
.filter(MaterialBase.material_type != None, MaterialBase.material_type != '') \
.distinct().all()
+ sorted_types = sorted([t[0] for t in types])
+
+ # 3. 公司
+ companies = db.session.query(MaterialBase.company_name) \
+ .filter(MaterialBase.company_name != None, MaterialBase.company_name != '') \
+ .distinct().all()
+ sorted_companies = sorted([c[0] for c in companies])
return {
- "categories": [c[0] for c in categories],
- "types": [t[0] for t in types]
+ "categories": sorted_categories,
+ "types": sorted_types,
+ "companies": sorted_companies
}
except Exception as e:
traceback.print_exc()
- return {"categories": [], "types": []}
+ return {"categories": [], "types": [], "companies": []}
@staticmethod
def create_material(data):
"""新增基础信息"""
try:
- # 0. 基础校验
if not data.get('name') or not data.get('spec'):
raise ValueError("名称和规格型号不能为空")
- # 1. 查重
exist = MaterialBase.query.filter_by(
name=data['name'],
spec_model=data['spec']
@@ -197,8 +190,9 @@ class MaterialBaseService:
if exist:
raise ValueError(f"已存在相同名称和规格的数据 (ID: {exist.id})")
- # 2. 创建对象 (列表转JSON字符串)
new_material = MaterialBase(
+ # [修改] 移除了 'IRIS' 默认值
+ company_name=data.get('companyName'),
name=data['name'],
common_name=data.get('commonName'),
spec_model=data['spec'],
@@ -206,7 +200,6 @@ class MaterialBaseService:
material_type=data.get('type'),
unit=data.get('unit'),
visibility_level=data.get('visibilityLevel'),
- # 修改:将列表 dumps 为字符串
manual_link=json.dumps(data.get('generalManual', [])),
product_image=json.dumps(data.get('generalImage', [])),
is_enabled=True if data.get('isEnabled', 1) == 1 else False
@@ -229,6 +222,7 @@ class MaterialBaseService:
raise ValueError("数据不存在")
# 更新字段
+ if 'companyName' in data: material.company_name = data['companyName']
if 'name' in data: material.name = data['name']
if 'commonName' in data: material.common_name = data['commonName']
if 'spec' in data: material.spec_model = data['spec']
@@ -237,7 +231,6 @@ class MaterialBaseService:
if 'unit' in data: material.unit = data['unit']
if 'visibilityLevel' in data: material.visibility_level = data['visibilityLevel']
- # 修改:将列表 dumps 为字符串
if 'generalManual' in data:
material.manual_link = json.dumps(data['generalManual'])
if 'generalImage' in data:
@@ -266,10 +259,6 @@ class MaterialBaseService:
buy_usage_count = StockBuy.query.filter_by(base_id=m_id).count()
semi_usage_count = StockSemi.query.filter_by(base_id=m_id).count()
- # 如果需要检查成品和服务,可以解开注释
- # from app.models.inbound.product import StockProduct
- # prod_usage_count = StockProduct.query.filter_by(base_id=m_id).count()
-
total_usage = buy_usage_count + semi_usage_count
if total_usage > 0:
diff --git a/inventory-web/src/App.vue b/inventory-web/src/App.vue
index bf657bd..52c6f31 100644
--- a/inventory-web/src/App.vue
+++ b/inventory-web/src/App.vue
@@ -82,7 +82,7 @@ const handleLogout = () => {
diff --git a/inventory-web/src/views/material/list.vue b/inventory-web/src/views/material/list.vue
index dae6349..025fddb 100644
--- a/inventory-web/src/views/material/list.vue
+++ b/inventory-web/src/views/material/list.vue
@@ -11,6 +11,18 @@
@input="handleInputSearch"
/>
+
+
+
+
+
@@ -105,6 +118,13 @@
style="width: 100%; margin-top: 15px"
>
+
+
+
+ {{ scope.row.companyName || '-' }}
+
+
+
@@ -114,7 +134,7 @@
-
+
{{ scope.row.category || '-' }}
@@ -196,19 +216,6 @@
-
-
-
-
-
+
+
+
+
+
+ * 必须构成4层结构
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+ (0低-9高)
+
+
-
-
- (0为最低,9为最高)
-
-