Compare commits

..

3 Commits

Author SHA1 Message Date
c52d360cbb 一键清零和单位转换 2025-12-23 18:21:44 +08:00
76b16df32c 模糊搜索输入框 2025-12-23 16:09:50 +08:00
58605b1f92 编辑款式下拉框修复 2025-12-23 12:35:07 +08:00
7 changed files with 499 additions and 393 deletions

View File

@@ -32,6 +32,7 @@ class DatabaseManager:
CREATE TABLE IF NOT EXISTS fabrics ( CREATE TABLE IF NOT EXISTS fabrics (
model TEXT PRIMARY KEY, model TEXT PRIMARY KEY,
category TEXT DEFAULT '未分类', category TEXT DEFAULT '未分类',
fabric_type TEXT,
supplier TEXT, supplier TEXT,
color TEXT, color TEXT,
width REAL, width REAL,
@@ -47,6 +48,7 @@ class DatabaseManager:
# 为fabrics表添加索引 # 为fabrics表添加索引
conn.execute('CREATE INDEX IF NOT EXISTS idx_fabrics_category ON fabrics(category)') conn.execute('CREATE INDEX IF NOT EXISTS idx_fabrics_category ON fabrics(category)')
conn.execute('CREATE INDEX IF NOT EXISTS idx_fabrics_fabric_type ON fabrics(fabric_type)')
conn.execute('CREATE INDEX IF NOT EXISTS idx_fabrics_supplier ON fabrics(supplier)') conn.execute('CREATE INDEX IF NOT EXISTS idx_fabrics_supplier ON fabrics(supplier)')
# 衣服款号表 # 衣服款号表
@@ -66,6 +68,7 @@ class DatabaseManager:
style_number TEXT, style_number TEXT,
category TEXT, category TEXT,
fabric_type TEXT, fabric_type TEXT,
model TEXT,
usage_per_piece REAL, usage_per_piece REAL,
unit TEXT DEFAULT '', unit TEXT DEFAULT '',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP, created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
@@ -77,12 +80,21 @@ class DatabaseManager:
# 为garment_materials表添加索引 # 为garment_materials表添加索引
conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_style ON garment_materials(style_number)') conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_style ON garment_materials(style_number)')
conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_category ON garment_materials(category)') conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_category ON garment_materials(category)')
conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_model ON garment_materials(model)')
# 添加新字段(如果不存在) # 添加新字段(如果不存在)
try: try:
conn.execute("ALTER TABLE garment_materials ADD COLUMN fabric_type TEXT") conn.execute("ALTER TABLE garment_materials ADD COLUMN fabric_type TEXT")
except: except:
pass pass
try:
conn.execute("ALTER TABLE garment_materials ADD COLUMN model TEXT")
except:
pass
try:
conn.execute("ALTER TABLE fabrics ADD COLUMN fabric_type TEXT")
except:
pass
try: try:
conn.execute("ALTER TABLE fabrics ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP") conn.execute("ALTER TABLE fabrics ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP")
except: except:
@@ -132,6 +144,21 @@ class DatabaseManager:
except: except:
pass pass
# 数据迁移将fabrics表中category字段的"类目-类型"格式拆分成两个字段
try:
cursor = conn.execute("SELECT model, category FROM fabrics WHERE category LIKE '%-%' AND (fabric_type IS NULL OR fabric_type = '')")
rows = cursor.fetchall()
for model, category in rows:
if '-' in category:
parts = category.split('-', 1)
new_category = parts[0]
new_fabric_type = parts[1]
conn.execute("UPDATE fabrics SET category = ?, fabric_type = ? WHERE model = ?",
(new_category, new_fabric_type, model))
conn.commit()
except:
pass
# 管理员设置表 # 管理员设置表
conn.execute(''' conn.execute('''
CREATE TABLE IF NOT EXISTS admin_settings ( CREATE TABLE IF NOT EXISTS admin_settings (
@@ -246,14 +273,10 @@ def get_fabric_categories(db_path):
try: try:
with get_db_connection(db_path) as conn: with get_db_connection(db_path) as conn:
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT SELECT DISTINCT category
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, 1, INSTR(category, '-') - 1)
ELSE category
END as major_category
FROM fabrics FROM fabrics
WHERE category IS NOT NULL AND category != '' WHERE category IS NOT NULL AND category != ''
ORDER BY major_category ORDER BY category
""") """)
categories = set() categories = set()
for row in cursor.fetchall(): for row in cursor.fetchall():
@@ -272,19 +295,15 @@ def get_fabric_types_by_category(db_path, category):
try: try:
with get_db_connection(db_path) as conn: with get_db_connection(db_path) as conn:
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT SELECT DISTINCT fabric_type
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
ELSE '默认类型'
END as fabric_type
FROM fabrics FROM fabrics
WHERE category LIKE ? OR category = ? WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''
ORDER BY fabric_type ORDER BY fabric_type
""", (f"{category}-%", category)) """, (category,))
types = [] types = []
for row in cursor.fetchall(): for row in cursor.fetchall():
if row[0] and row[0] != '默认类型': if row[0] and row[0].strip():
types.append(row[0]) types.append(row[0])
return types return types
except: except:

Binary file not shown.

View File

@@ -86,45 +86,55 @@ class FabricManager(QMainWindow):
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute(''' cursor = conn.execute('''
SELECT category, fabric_type, usage_per_piece, unit SELECT model, category, fabric_type, usage_per_piece, unit
FROM garment_materials FROM garment_materials
WHERE style_number = ? WHERE style_number = ?
''', (style_number,)) ''', (style_number,))
rows = cursor.fetchall() rows = cursor.fetchall()
inserted = 0 inserted = 0
for category, fabric_type, usage_per_piece, unit in rows: for model, category, fabric_type, usage_per_piece, unit in rows:
if usage_per_piece == 0: if usage_per_piece == 0:
continue continue
# 获取该原料在入库时使用的单位 # 优先使用精确原料型号model如无型号则退回到分类名称兼容旧数据
raw_identifier = model if model else category
# 获取该原料在入库时使用的单位(最近一次入库)
stock_cursor = conn.execute(''' stock_cursor = conn.execute('''
SELECT unit FROM fabric_stock_in SELECT unit FROM fabric_stock_in
WHERE model = ? WHERE model = ?
ORDER BY purchase_date DESC ORDER BY purchase_date DESC
LIMIT 1 LIMIT 1
''', (category,)) ''', (raw_identifier,))
stock_unit_row = stock_cursor.fetchone() stock_unit_row = stock_cursor.fetchone()
# 如果有入库记录,使用入库单位;否则使用原来的单位 total_usage = usage_per_piece * quantity * (1 + loss_rate)
# 如果有入库记录,则按入库单位扣减库存;必要时进行单位换算
if stock_unit_row: if stock_unit_row:
stock_unit = stock_unit_row[0] stock_unit = stock_unit_row[0]
# 如果单位不同,需要转换
if unit != stock_unit: if unit != stock_unit:
consume_qty = self.convert_unit_value(usage_per_piece * quantity * (1 + loss_rate), unit, stock_unit, category) # 单位不同,尝试进行单位转换(米/码/公斤互转依赖面料幅宽和克重)
consume_qty = self.convert_unit_value(
total_usage,
unit,
stock_unit,
fabric_model=model if model else None
)
final_unit = stock_unit final_unit = stock_unit
else: else:
consume_qty = usage_per_piece * quantity * (1 + loss_rate) consume_qty = total_usage
final_unit = unit final_unit = unit
else: else:
# 没有入库记录,使用原单位 # 没有入库记录,只能按原单位记录消耗
consume_qty = usage_per_piece * quantity * (1 + loss_rate) consume_qty = total_usage
final_unit = unit final_unit = unit
conn.execute(''' conn.execute('''
INSERT INTO fabric_consumption INSERT INTO fabric_consumption
(style_number, model, single_usage, quantity_made, loss_rate, consume_quantity, consume_date, unit) (style_number, model, single_usage, quantity_made, loss_rate, consume_quantity, consume_date, unit)
VALUES (?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
''', (style_number, category, usage_per_piece, quantity, loss_rate, consume_qty, datetime.now().strftime('%Y-%m-%d'), final_unit)) ''', (style_number, raw_identifier, usage_per_piece, quantity, loss_rate, consume_qty, datetime.now().strftime('%Y-%m-%d'), final_unit))
inserted += 1 inserted += 1
conn.commit() conn.commit()
if inserted > 0: if inserted > 0:
@@ -177,12 +187,17 @@ class FabricManager(QMainWindow):
text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n" text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n"
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT category, fabric_type, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (style_number,)) cursor = conn.execute("SELECT category, fabric_type, model, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (style_number,))
for category, fabric_type, usage, unit in cursor.fetchall(): for category, fabric_type, model, usage, unit in cursor.fetchall():
if usage: if usage:
total = usage * qty * (1 + loss) total = usage * qty * (1 + loss)
# 显示材料名称(如果有类型则显示类目-类型,否则只显示类目 # 显示材料名称:优先显示型号,否则显示类目-类型,最后只显示类目
material_name = f"{category}-{fabric_type}" if fabric_type else category if model:
material_name = model
elif fabric_type:
material_name = f"{category}-{fabric_type}" if category else fabric_type
else:
material_name = category or "未命名材料"
text += f"{material_name}\n单件: {usage:.3f} {unit}\n总用量: {total:.3f} {unit}\n\n" text += f"{material_name}\n单件: {usage:.3f} {unit}\n总用量: {total:.3f} {unit}\n\n"
except Exception as e: except Exception as e:
text += "计算失败: " + str(e) text += "计算失败: " + str(e)
@@ -332,6 +347,7 @@ class FabricManager(QMainWindow):
CREATE TABLE IF NOT EXISTS fabrics ( CREATE TABLE IF NOT EXISTS fabrics (
model TEXT PRIMARY KEY, model TEXT PRIMARY KEY,
category TEXT DEFAULT '未分类', category TEXT DEFAULT '未分类',
fabric_type TEXT,
supplier TEXT, supplier TEXT,
color TEXT, color TEXT,
width REAL, width REAL,
@@ -356,6 +372,7 @@ class FabricManager(QMainWindow):
style_number TEXT, style_number TEXT,
category TEXT, category TEXT,
fabric_type TEXT, fabric_type TEXT,
model TEXT,
usage_per_piece REAL, usage_per_piece REAL,
unit TEXT DEFAULT '' unit TEXT DEFAULT ''
) )
@@ -364,6 +381,30 @@ class FabricManager(QMainWindow):
# 添加fabric_type列如果不存在 # 添加fabric_type列如果不存在
try: try:
conn.execute("ALTER TABLE garment_materials ADD COLUMN fabric_type TEXT") conn.execute("ALTER TABLE garment_materials ADD COLUMN fabric_type TEXT")
except:
pass
# 添加model列如果不存在
try:
conn.execute("ALTER TABLE garment_materials ADD COLUMN model TEXT")
except:
pass
# 添加fabrics表的fabric_type列如果不存在
try:
conn.execute("ALTER TABLE fabrics ADD COLUMN fabric_type TEXT")
except:
pass
# 数据迁移将fabrics表中category字段的"类目-类型"格式拆分成两个字段
try:
cursor = conn.execute("SELECT model, category FROM fabrics WHERE category LIKE '%-%' AND (fabric_type IS NULL OR fabric_type = '')")
rows = cursor.fetchall()
for model, category in rows:
if '-' in category:
parts = category.split('-', 1)
new_category = parts[0]
new_fabric_type = parts[1]
conn.execute("UPDATE fabrics SET category = ?, fabric_type = ? WHERE model = ?",
(new_category, new_fabric_type, model))
conn.commit()
except: except:
pass # 列已存在 pass # 列已存在

View File

@@ -10,107 +10,68 @@ from PyQt5.QtWidgets import (
QPushButton, QComboBox, QTableWidget, QTableWidgetItem, QHeaderView, QPushButton, QComboBox, QTableWidget, QTableWidgetItem, QHeaderView,
QMessageBox, QFileDialog, QDoubleSpinBox, QWidget, QCompleter QMessageBox, QFileDialog, QDoubleSpinBox, QWidget, QCompleter
) )
from PyQt5.QtCore import Qt, QStringListModel, QTimer from PyQt5.QtCore import Qt, QTimer, QSortFilterProxyModel
from PyQt5.QtGui import QPixmap from PyQt5.QtGui import QPixmap
from database import get_db_connection from database import get_db_connection
class SearchableComboBox(QComboBox): class SearchableComboBox(QComboBox):
"""支持模糊搜索的下拉框""" """支持模糊搜索的下拉框 - 基于 QSortFilterProxyModel 和 QCompleter"""
def __init__(self, parent=None): def __init__(self, parent=None):
super().__init__(parent) super(SearchableComboBox, self).__init__(parent)
self.setFocusPolicy(Qt.StrongFocus)
self.setEditable(True) self.setEditable(True)
self.setInsertPolicy(QComboBox.NoInsert) self.setInsertPolicy(QComboBox.NoInsert)
# 存储所有选 # 添加过滤模型来过滤匹配
self.all_items = [] self.pFilterModel = QSortFilterProxyModel(self)
self.all_data = [] self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
self.is_filtering = False self.pFilterModel.setSourceModel(self.model())
# 设置自动完成 # 添加自动完成器,使用过滤模型
self.completer = QCompleter(self) self.completer = QCompleter(self.pFilterModel, self)
self.completer.setCompletionMode(QCompleter.PopupCompletion) # 始终显示所有(过滤后的)完成项
self.completer.setCaseSensitivity(Qt.CaseInsensitive) self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
self.completer.setFilterMode(Qt.MatchContains)
self.setCompleter(self.completer) self.setCompleter(self.completer)
# 连接信号 # 连接信号
self.lineEdit().textChanged.connect(self.on_text_changed) self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
self.completer.activated.connect(self.on_completer_activated)
def addItem(self, text, userData=None): # 当从自动完成器中选择项时,从组合框中选择对应的项
"""添加选项""" def on_completer_activated(self, text):
# 临时断开信号连接防止textChanged触发on_text_changed if text:
self.lineEdit().textChanged.disconnect() index = self.findText(text)
super().addItem(text, userData) self.setCurrentIndex(index)
if text not in self.all_items: self.activated[str].emit(self.itemText(index))
self.all_items.append(text)
self.all_data.append(userData)
self.update_completer()
# 重新连接信号
self.lineEdit().textChanged.connect(self.on_text_changed)
def addItems(self, texts): # 当模型改变时,同时更新过滤器和自动完成器的模型
"""批量添加选项""" def setModel(self, model):
for text in texts: super(SearchableComboBox, self).setModel(model)
self.addItem(text) self.pFilterModel.setSourceModel(model)
self.completer.setModel(self.pFilterModel)
def clear(self): # 当模型列改变时,同时更新过滤器和自动完成器的模型列
"""清空所有选项""" def setModelColumn(self, column):
if not self.is_filtering: self.completer.setCompletionColumn(column)
super().clear() self.pFilterModel.setFilterKeyColumn(column)
self.all_items.clear() super(SearchableComboBox, self).setModelColumn(column)
self.all_data.clear()
self.update_completer()
def reset_items(self):
"""重置所有选项"""
# 临时断开信号连接防止textChanged触发on_text_changed
self.lineEdit().textChanged.disconnect()
self.is_filtering = True
super().clear()
for i, item in enumerate(self.all_items):
super().addItem(item, self.all_data[i] if i < len(self.all_data) else None)
self.is_filtering = False
# 重新连接信号
self.lineEdit().textChanged.connect(self.on_text_changed)
def update_completer(self):
"""更新自动完成列表"""
model = QStringListModel(self.all_items)
self.completer.setModel(model)
def on_text_changed(self, text):
"""文本改变时的处理"""
if self.is_filtering:
return
if not text or text in ["—— 选择型号 ——"]:
self.reset_items()
# 如果获得焦点且有选项,显示下拉列表
if self.hasFocus() and self.count() > 0:
self.showPopup()
return
# 模糊搜索匹配
filtered_items = []
filtered_data = []
for i, item in enumerate(self.all_items):
if text.lower() in item.lower():
filtered_items.append(item)
filtered_data.append(self.all_data[i] if i < len(self.all_data) else None)
# 更新下拉列表
self.is_filtering = True
super().clear()
for i, item in enumerate(filtered_items):
super().addItem(item, filtered_data[i])
self.is_filtering = False
# 如果有匹配项且获得焦点,显示下拉列表
if filtered_items and self.hasFocus():
self.showPopup()
def setDefaultText(self, text):
"""设置默认文本 - 兼容方法"""
line_edit = self.lineEdit()
if line_edit:
line_edit.blockSignals(True)
line_edit.setText(text)
line_edit.blockSignals(False)
# 尝试找到匹配的项
index = self.findText(text)
if index >= 0:
self.setCurrentIndex(index)
else:
self.setCurrentIndex(-1)
class GarmentLibraryDialog(QDialog): class GarmentLibraryDialog(QDialog):
"""服装库管理对话框""" """服装库管理对话框"""
@@ -355,40 +316,12 @@ class GarmentEditDialog(QDialog):
"""加载材料列表""" """加载材料列表"""
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT category, fabric_type, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (self.style_number,)) cursor = conn.execute("SELECT category, fabric_type, model, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (self.style_number,))
for category, fabric_type, usage, unit in cursor.fetchall(): for category, fabric_type, model, usage, unit in cursor.fetchall():
display_category = "" # 直接使用数据库中的三个字段
display_type = "" display_category = category or ""
display_model = "" display_type = fabric_type or ""
display_model = model or ""
# category字段可能存储型号或类目-类型组合
if category:
# 首先检查是否是型号在fabrics表中查找
fabric_cursor = conn.execute("SELECT category, model FROM fabrics WHERE model = ?", (category,))
fabric_row = fabric_cursor.fetchone()
if fabric_row:
# 是型号从fabrics表获取类目信息
fabric_category, model = fabric_row
display_model = model
if fabric_category and "-" in fabric_category:
parts = fabric_category.split("-", 1)
display_category = parts[0]
display_type = parts[1]
else:
display_category = fabric_category or ""
else:
# 不是型号,按类目-类型格式解析
if "-" in category:
parts = category.split("-", 1)
display_category = parts[0]
display_type = parts[1]
else:
display_category = category
# 如果有单独的fabric_type字段优先使用
if fabric_type:
display_type = fabric_type
self.add_material_row(display_category, display_type, usage or 0, unit or "", display_model) self.add_material_row(display_category, display_type, usage or 0, unit or "", display_model)
except Exception as e: except Exception as e:
@@ -403,37 +336,30 @@ class GarmentEditDialog(QDialog):
def add_material_row(self, category="", fabric_type="", usage=0.0, unit="", model=""): def add_material_row(self, category="", fabric_type="", usage=0.0, unit="", model=""):
"""添加材料行""" """添加材料行"""
print("add_material_row", category, fabric_type, usage, unit, model)
row = self.material_table.rowCount() row = self.material_table.rowCount()
self.material_table.insertRow(row) self.material_table.insertRow(row)
# 列0: 类目下拉框 # 列0: 类目下拉框
cat_combo = QComboBox() cat_combo = QComboBox()
cat_combo.setEditable(True) cat_combo.setEditable(False)
# 最后添加自定义选项 # 最后添加自定义选项
cat_combo.addItem("—— 自定义类目 ——") cat_combo.addItem("—— 自定义类目 ——")
# 先添加所有类目选项 # 先添加所有类目选项
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
# 只获取纯类目(提取"-"前面的部分)
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT SELECT DISTINCT category
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, 1, INSTR(category, '-') - 1)
ELSE category
END as major_category
FROM fabrics FROM fabrics
WHERE category IS NOT NULL AND category != '' WHERE category IS NOT NULL AND category != ''
ORDER BY major_category ORDER BY category
""") """)
categories = set() categories = set()
for cat_row in cursor.fetchall(): for cat_row in cursor.fetchall():
if cat_row[0] and cat_row[0].strip(): if cat_row[0] and cat_row[0].strip():
categories.add(cat_row[0]) categories.add(cat_row[0])
# 添加默认类目
categories.update(["布料", "辅料", "其他"])
for cat in sorted(categories): for cat in sorted(categories):
cat_combo.addItem(cat) cat_combo.addItem(cat)
except: except:
@@ -445,80 +371,63 @@ class GarmentEditDialog(QDialog):
if category: if category:
cat_combo.setCurrentText(category) cat_combo.setCurrentText(category)
else: else:
# 如果没有指定类目,默认选择第一个实际类目而不是"自定义类目" # 如果没有指定类目,默认选择"—— 自定义类目 ——"索引0
if cat_combo.count() > 1: print("没有指定类目,默认选择'—— 自定义类目 ——'索引0")
print(cat_combo.count())
print(cat_combo.currentIndex())
# 打印所有选项
for i in range(cat_combo.count()):
print(cat_combo.itemText(i))
cat_combo.setCurrentIndex(0) cat_combo.setCurrentIndex(0)
cat_combo.currentTextChanged.connect(lambda text, r=row: self.on_category_changed(text, r))
self.material_table.setCellWidget(row, 0, cat_combo) self.material_table.setCellWidget(row, 0, cat_combo)
# 列1: 类型下拉框 # 列1: 类型下拉框
type_combo = QComboBox() type_combo = QComboBox()
type_combo.setEditable(True) type_combo.setEditable(False)
# 最后添加选择提示
type_combo.addItem("—— 选择类型 ——")
# 先添加所有类型选项 # 先添加所有类型选项
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT SELECT DISTINCT fabric_type
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
ELSE '默认类型'
END as fabric_type
FROM fabrics FROM fabrics
WHERE category IS NOT NULL AND category != '' WHERE fabric_type IS NOT NULL AND fabric_type != ''
ORDER BY fabric_type ORDER BY fabric_type
""") """)
types = cursor.fetchall() types = cursor.fetchall()
for type_row in types: for type_row in types:
if type_row[0] and type_row[0] != '默认类型': if type_row[0] and type_row[0].strip():
type_combo.addItem(type_row[0]) type_combo.addItem(type_row[0])
except: except:
pass pass
# 最后添加选择提示
type_combo.addItem("—— 选择类型 ——")
if fabric_type: if fabric_type:
type_combo.setCurrentText(fabric_type) type_combo.setCurrentText(fabric_type)
else: else:
# 如果没有指定类型,默认选择第一个实际类型而不是"选择类型" # 如果没有指定类型,默认选择"—— 选择类型 ——"索引0
if type_combo.count() > 1: print("没有指定类型,默认选择'—— 选择类型 ——'索引0")
print(type_combo.count())
print(type_combo.currentIndex())
# 打印所有选项
for i in range(type_combo.count()):
print(type_combo.itemText(i))
type_combo.setCurrentIndex(0) type_combo.setCurrentIndex(0)
type_combo.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r))
self.material_table.setCellWidget(row, 1, type_combo) self.material_table.setCellWidget(row, 1, type_combo)
# 列2: 型号下拉框(支持模糊搜索) # 列2: 型号下拉框(支持模糊搜索)
model_combo = SearchableComboBox() model_combo = SearchableComboBox()
model_combo.addItem("—— 选择型号 ——") model_combo.addItem("—— 选择型号 ——")
# 先将下拉框添加到表格中这样update_model_combo_range才能获取到类目和类型
# 初始化时加载所有型号
try:
with self.get_conn() as conn:
cursor = conn.execute("""
SELECT DISTINCT model, color, unit
FROM fabrics
ORDER BY model
""")
models = cursor.fetchall()
for model_row in models:
model, color, unit = model_row
# 显示格式:型号-颜色(如果有颜色的话)
display_text = model
if color and color.strip():
display_text = f"{model}-{color}"
model_combo.addItem(display_text, model)
except Exception as e:
pass
# 确保默认选中第一项("—— 选择型号 ——"
model_combo.setCurrentIndex(0)
model_combo.currentTextChanged.connect(lambda text, r=row: self.on_model_selected(text, r))
self.material_table.setCellWidget(row, 2, model_combo) self.material_table.setCellWidget(row, 2, model_combo)
# 初始化时根据类目和类型加载对应的型号
self.update_model_combo_range(model_combo, row)
# 列3: 单件用量 # 列3: 单件用量
usage_spin = QDoubleSpinBox() usage_spin = QDoubleSpinBox()
usage_spin.setRange(0, 1000) usage_spin.setRange(0, 1000)
@@ -539,38 +448,121 @@ class GarmentEditDialog(QDialog):
self.material_table.setCellWidget(row, 5, del_btn) self.material_table.setCellWidget(row, 5, del_btn)
# 初始化类型和型号选项 # 初始化类型和型号选项
self.on_category_changed(cat_combo.currentText(), row) # self.on_category_changed(cat_combo.currentText(), row)
# 如果没有选择具体类目,初始化时显示全部型号 # 如果没有选择具体类目,初始化时显示全部型号
if cat_combo.currentText() == "—— 自定义类目 ——": # if cat_combo.currentText() == "—— 自定义类目 ——":
self.on_type_changed("—— 选择类型 ——", row) # self.on_type_changed("—— 选择类型 ——", row)
# 如果有指定的型号,需要在初始化完成后设置 # 如果有指定的型号,需要在初始化完成后设置
if model: # if model:
# 先设置类型(如果有的话) # # 先设置类型(如果有的话)
if fabric_type: # if fabric_type:
type_combo.setCurrentText(fabric_type) # type_combo.setCurrentText(fabric_type)
self.on_type_changed(fabric_type, row) # self.on_type_changed(fabric_type, row)
# 然后设置型号 - 使用SearchableComboBox的setCurrentText方法 # # 然后设置型号
model_combo = self.material_table.cellWidget(row, 2) # model_combo = self.material_table.cellWidget(row, 2)
# if model_combo:
# # 确保型号在选项列表中
# found = False
# for i in range(model_combo.count()):
# item_data = model_combo.itemData(i)
# item_text = model_combo.itemText(i)
# if item_data == model or item_text == model:
# model_combo.setCurrentIndex(i)
# found = True
# break
cat_combo.currentTextChanged.connect(lambda text, r=row: self.on_category_changed(text, r))
type_combo.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r))
# 当用户真正选择了某个型号(包括通过模糊搜索补全选择),再联动类目和类型
model_combo.activated[str].connect(lambda text, r=row: self.on_model_selected(text, r))
def update_model_combo_range(self, model_combo, row):
print("update_model_combo_range", model_combo, row)
"""更新型号下拉框的搜索范围"""
cat_combo = self.material_table.cellWidget(row, 0)
type_combo = self.material_table.cellWidget(row, 1)
category_text = cat_combo.currentText() if cat_combo else ""
type_text = type_combo.currentText() if type_combo else ""
# 阻止信号防止触发on_model_selected
model_combo.blockSignals(True)
line_edit = model_combo.lineEdit()
if line_edit:
line_edit.blockSignals(True)
try:
with self.get_conn() as conn:
# 根据类目和类型构建查询条件
if category_text and category_text != "—— 自定义类目 ——" and type_text and type_text != "—— 选择类型 ——":
# 同时根据类目和类型过滤
cursor = conn.execute("""
SELECT DISTINCT model, color, unit
FROM fabrics
WHERE category = ? AND fabric_type = ?
ORDER BY model
""", (category_text, type_text))
elif category_text and category_text != "—— 自定义类目 ——":
# 只根据类目过滤
cursor = conn.execute("""
SELECT DISTINCT model, color, unit
FROM fabrics
WHERE category = ?
ORDER BY model
""", (category_text,))
elif type_text and type_text != "—— 选择类型 ——":
# 只根据类型过滤
cursor = conn.execute("""
SELECT DISTINCT model, color, unit
FROM fabrics
WHERE fabric_type = ?
ORDER BY model
""", (type_text,))
else:
# 显示所有型号
cursor = conn.execute("""
SELECT DISTINCT model, color, unit
FROM fabrics
ORDER BY model
""")
# 保存当前用户输入的文本(如果有)
current_text = line_edit.text() if line_edit else ""
cursor_position = line_edit.cursorPosition() if line_edit else 0
print("current_text", current_text)
print("cursor_position", cursor_position)
# 清空并重新填充型号下拉框
model_combo.clear()
models = cursor.fetchall()
for model_row in models:
model, color, unit = model_row
# 显示格式:型号-颜色(如果有颜色的话)
display_text = model
if color and color.strip():
display_text = f"{model}-{color}"
model_combo.addItem(display_text, model)
# 恢复用户输入的文本,如果没有输入则设置默认文本
if line_edit:
if current_text and current_text != "—— 选择型号 ——":
line_edit.setText(current_text)
line_edit.setCursorPosition(cursor_position)
else:
if isinstance(model_combo, SearchableComboBox): if isinstance(model_combo, SearchableComboBox):
# 确保型号在选项列表中 model_combo.setDefaultText("—— 选择型号 ——")
found = False else:
for i in range(model_combo.count()): model_combo.setCurrentIndex(0)
item_data = model_combo.itemData(i) except Exception as e:
item_text = model_combo.itemText(i) pass
if item_data == model or item_text == model: finally:
model_combo.setCurrentIndex(i) if line_edit:
found = True line_edit.blockSignals(False)
break model_combo.blockSignals(False)
# 如果没找到直接设置文本SearchableComboBox支持
if not found:
model_combo.setCurrentText(model)
def on_category_changed(self, category_text, row): def on_category_changed(self, category_text, row):
"""当类目改变时,更新类型下拉框""" """当类目改变时,更新类型下拉框"""
print("on_category_changed", category_text, row)
type_combo = self.material_table.cellWidget(row, 1) type_combo = self.material_table.cellWidget(row, 1)
model_combo = self.material_table.cellWidget(row, 2) model_combo = self.material_table.cellWidget(row, 2)
@@ -578,144 +570,130 @@ class GarmentEditDialog(QDialog):
type_combo.clear() type_combo.clear()
type_combo.addItem("—— 选择类型 ——") type_combo.addItem("—— 选择类型 ——")
# 重新初始化型号下拉框,显示所有型号
model_combo.clear()
model_combo.addItem("—— 选择型号 ——")
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
# 加载所有类型 # 加载所有类型
if category_text and category_text != "—— 自定义类目 ——":
# 如果选择了具体类目,则过滤
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT SELECT DISTINCT fabric_type
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
ELSE '默认类型'
END as fabric_type
FROM fabrics FROM fabrics
WHERE category IS NOT NULL AND category != '' WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''
ORDER BY fabric_type
""", (category_text,))
else:
# 加载所有类型
cursor = conn.execute("""
SELECT DISTINCT fabric_type
FROM fabrics
WHERE fabric_type IS NOT NULL AND fabric_type != ''
ORDER BY fabric_type ORDER BY fabric_type
""") """)
# 如果选择了具体类目,则过滤
if category_text and category_text != "—— 自定义类目 ——":
cursor = conn.execute("""
SELECT DISTINCT
CASE
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
ELSE '默认类型'
END as fabric_type
FROM fabrics
WHERE category LIKE ? OR category = ?
ORDER BY fabric_type
""", (f"{category_text}-%", category_text))
types = cursor.fetchall() types = cursor.fetchall()
for type_row in types: for type_row in types:
if type_row[0] and type_row[0] != '默认类型': if type_row[0] and type_row[0].strip():
type_combo.addItem(type_row[0]) type_combo.addItem(type_row[0])
# 连接类型改变事件 # 连接类型改变事件
type_combo.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r)) type_combo.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r))
# 加载所有型号到型号下拉框 # 更新型号下拉框的搜索范围
cursor = conn.execute(""" self.update_model_combo_range(model_combo, row)
SELECT DISTINCT model, color, unit
FROM fabrics
ORDER BY model
""")
models = cursor.fetchall()
for model_row in models:
model, color, unit = model_row
# 显示格式:型号-颜色(如果有颜色的话)
display_text = model
if color and color.strip():
display_text = f"{model}-{color}"
model_combo.addItem(display_text, model)
# 确保默认选中第一项("—— 选择型号 ——"
model_combo.setCurrentIndex(0)
except Exception as e: except Exception as e:
pass pass
def on_type_changed(self, type_text, row): def on_type_changed(self, type_text, row):
"""当类型改变时,更新型号下拉框""" """当类型改变时,更新类目和型号下拉框"""
print("on_type_changed", type_text, row)
cat_combo = self.material_table.cellWidget(row, 0) cat_combo = self.material_table.cellWidget(row, 0)
model_combo = self.material_table.cellWidget(row, 2) model_combo = self.material_table.cellWidget(row, 2)
# 重新初始化型号下拉框,显示所有型号 if not model_combo:
if hasattr(model_combo, 'clear'): return
model_combo.clear()
model_combo.addItem("—— 选择型号 ——")
# 始终显示所有型号,不进行过滤 # 如果选择了具体类型,自动选中该类型对应的类目
if cat_combo and type_text and type_text != "—— 选择类型 ——":
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
# 查询该类型对应的类目
cursor = conn.execute(""" cursor = conn.execute("""
SELECT DISTINCT model, color, unit SELECT DISTINCT category
FROM fabrics FROM fabrics
ORDER BY model WHERE fabric_type = ? AND category IS NOT NULL AND category != ''
""") ORDER BY category
models = cursor.fetchall() LIMIT 1
for model_row in models: """, (type_text,))
model, color, unit = model_row row_db = cursor.fetchone()
# 显示格式:型号-颜色(如果有颜色的话) if row_db and row_db[0]:
display_text = model category = row_db[0].strip()
if color and color.strip(): # 在类目下拉框中查找并选中该类目
display_text = f"{model}-{color}" index = cat_combo.findText(category)
model_combo.addItem(display_text, model) if index >= 0:
cat_combo.blockSignals(True)
# 确保默认选中第一项("—— 选择型号 ——" cat_combo.setCurrentIndex(index)
model_combo.setCurrentIndex(0) cat_combo.blockSignals(False)
except Exception as e: except Exception as e:
pass pass
# 更新型号下拉框的搜索范围
self.update_model_combo_range(model_combo, row)
def on_model_selected(self, model_text, row): def on_model_selected(self, model_text, row):
"""当型号选择时,自动设置单位并填充类目和类型""" """当型号选择时,自动设置单位并填充类目和类型"""
if not model_text or model_text == "—— 选择型号 ——": print("on_model_selected", model_text, row)
return # 先获取所有需要的控件
cat_combo = self.material_table.cellWidget(row, 0) cat_combo = self.material_table.cellWidget(row, 0)
type_combo = self.material_table.cellWidget(row, 1) type_combo = self.material_table.cellWidget(row, 1)
model_combo = self.material_table.cellWidget(row, 2) model_combo = self.material_table.cellWidget(row, 2)
unit_combo = self.material_table.cellWidget(row, 4) unit_combo = self.material_table.cellWidget(row, 4)
# 获取选中项的数据 if not model_text or model_text == "—— 选择型号 ——":
current_index = model_combo.currentIndex() # 空选择,不做联动
if current_index > 0: return
model = model_combo.itemData(current_index)
if model: # 从显示文本中解析真实型号(例如 "M001-红" -> "M001"
display_text = model_text.strip()
base_model = display_text.split("-", 1)[0] if "-" in display_text else display_text
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT category, unit FROM fabrics WHERE model = ?", (model,)) cursor = conn.execute(
"SELECT category, fabric_type, unit FROM fabrics WHERE model = ?",
(base_model,)
)
row_db = cursor.fetchone() row_db = cursor.fetchone()
if row_db: if row_db:
category, unit = row_db category, fabric_type, unit = row_db
# 自动填充单位 # 自动填充单位
if unit: if unit:
unit_combo.setCurrentText(unit) unit_combo.setCurrentText(unit)
# 自动填充类目和类型 # 自动填充类目和类型,阻止信号以避免触发默认更新逻辑
if category: if category:
# 解析类目信息,可能是"类目-类型"格式或单独的类目 # 阻止类目、类型和型号的信号,避免触发默认更新逻辑
if '-' in category: cat_combo.blockSignals(True)
parts = category.split('-', 1) type_combo.blockSignals(True)
cat_text = parts[0] model_combo.blockSignals(True)
type_text = parts[1] if len(parts) > 1 else ""
# 设置类目 # 设置类目
cat_combo.setCurrentText(cat_text) cat_combo.setCurrentText(category)
# 更新类型下拉框选项 # 更新类型下拉框选项(直接调用,不会触发信号因为已经阻止了)
self.on_category_changed(cat_text, row) self.on_category_changed(category, row)
# 重新阻止信号因为on_category_changed内部可能恢复了信号
model_combo.blockSignals(True)
# 设置类型 # 设置类型
if type_text: if fabric_type:
type_combo.setCurrentText(type_text) type_combo.setCurrentText(fabric_type)
else:
# 只有类目,没有类型 # 恢复信号
cat_combo.setCurrentText(category) cat_combo.blockSignals(False)
self.on_category_changed(category, row) type_combo.blockSignals(False)
model_combo.blockSignals(False)
except: except:
pass pass
@@ -764,11 +742,9 @@ class GarmentEditDialog(QDialog):
usage = usage_widget.value() usage = usage_widget.value()
unit = unit_widget.currentText().strip() or "" unit = unit_widget.currentText().strip() or ""
# 分别存储类目、类型和型号信息 # 分别存储类目、类型和型号到对应字段
material_identifier = final_model if final_model else (f"{category}-{fabric_type}" if fabric_type else category) conn.execute("INSERT INTO garment_materials (style_number, category, fabric_type, model, usage_per_piece, unit) VALUES (?, ?, ?, ?, ?, ?)",
(style_number, category, fabric_type, final_model, usage, unit))
conn.execute("INSERT INTO garment_materials (style_number, category, fabric_type, usage_per_piece, unit) VALUES (?, ?, ?, ?, ?)",
(style_number, material_identifier, fabric_type, usage, unit))
conn.commit() conn.commit()
QMessageBox.information(self, "成功", "保存完成") QMessageBox.information(self, "成功", "保存完成")

13
main.py
View File

@@ -335,12 +335,17 @@ class FabricManager(QMainWindow):
text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n" text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n"
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT category, fabric_type, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (style_number,)) cursor = conn.execute("SELECT category, fabric_type, model, usage_per_piece, unit FROM garment_materials WHERE style_number = ? ORDER BY id", (style_number,))
for category, fabric_type, usage, unit in cursor.fetchall(): for category, fabric_type, model, usage, unit in cursor.fetchall():
if usage: if usage:
total = usage * qty * (1 + loss) total = usage * qty * (1 + loss)
# 显示材料名称(如果有类型则显示类目-类型,否则只显示类目 # 显示材料名称:优先显示型号,否则显示类目-类型,最后只显示类目
material_name = f"{category}-{fabric_type}" if fabric_type else category if model:
material_name = model
elif fabric_type:
material_name = f"{category}-{fabric_type}" if category else fabric_type
else:
material_name = category or "未命名材料"
text += f"{material_name}\n单件: {usage:.3f} {unit}\n总用量: {total:.3f} {unit}\n\n" text += f"{material_name}\n单件: {usage:.3f} {unit}\n总用量: {total:.3f} {unit}\n\n"
except Exception as e: except Exception as e:
text += "计算失败: " + str(e) text += "计算失败: " + str(e)

View File

@@ -76,17 +76,22 @@ class PurchaseOrderDialog(QDialog):
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute(''' cursor = conn.execute('''
SELECT category, fabric_type, usage_per_piece, unit SELECT category, fabric_type, model, usage_per_piece, unit
FROM garment_materials FROM garment_materials
WHERE style_number = ? AND usage_per_piece > 0 WHERE style_number = ? AND usage_per_piece > 0
ORDER BY id ORDER BY id
''', (self.style_number,)) ''', (self.style_number,))
rows = cursor.fetchall() rows = cursor.fetchall()
for category, fabric_type, usage_per_piece, unit in rows: for category, fabric_type, model, usage_per_piece, unit in rows:
total_usage = usage_per_piece * self.quantity * (1 + self.loss_rate) total_usage = usage_per_piece * self.quantity * (1 + self.loss_rate)
# 显示材料名称(如果有类型则显示类目-类型,否则只显示类目 # 显示材料名称:优先显示型号,否则显示类目-类型,最后只显示类目
material_name = f"{category}-{fabric_type}" if fabric_type else category if model:
material_name = model
elif fabric_type:
material_name = f"{category}-{fabric_type}" if category else fabric_type
else:
material_name = category or "未命名材料"
text += f"材料:{material_name}\n" text += f"材料:{material_name}\n"
text += f" 单件用量:{usage_per_piece:.3f} {unit}\n" text += f" 单件用量:{usage_per_piece:.3f} {unit}\n"
text += f" 总需采购:{total_usage:.3f} {unit}\n\n" text += f" 总需采购:{total_usage:.3f} {unit}\n\n"

View File

@@ -246,7 +246,7 @@ class RawMaterialLibraryDialog(QDialog):
"""加载主类目""" """加载主类目"""
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT DISTINCT CASE WHEN category LIKE '%-%' THEN SUBSTR(category, 1, INSTR(category, '-') - 1) ELSE category END FROM fabrics") cursor = conn.execute("SELECT DISTINCT category FROM fabrics WHERE category IS NOT NULL AND category != ''")
majors = set(row[0] for row in cursor.fetchall() if row[0]) majors = set(row[0] for row in cursor.fetchall() if row[0])
majors.update({"布料", "辅料", "其他"}) majors.update({"布料", "辅料", "其他"})
@@ -263,7 +263,7 @@ class RawMaterialLibraryDialog(QDialog):
"""加载添加界面的主类目""" """加载添加界面的主类目"""
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT DISTINCT CASE WHEN category LIKE '%-%' THEN SUBSTR(category, 1, INSTR(category, '-') - 1) ELSE category END FROM fabrics") cursor = conn.execute("SELECT DISTINCT category FROM fabrics WHERE category IS NOT NULL AND category != ''")
majors = set(row[0] for row in cursor.fetchall() if row[0]) majors = set(row[0] for row in cursor.fetchall() if row[0])
majors.update({"布料", "辅料", "其他"}) majors.update({"布料", "辅料", "其他"})
@@ -292,20 +292,12 @@ class RawMaterialLibraryDialog(QDialog):
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
if major in ("全部类目", ""): if major in ("全部类目", ""):
cursor = conn.execute("SELECT DISTINCT category FROM fabrics WHERE category LIKE '%-%'") cursor = conn.execute("SELECT DISTINCT fabric_type FROM fabrics WHERE fabric_type IS NOT NULL AND fabric_type != ''")
subs = set() subs = [row[0] for row in cursor.fetchall() if row[0]]
for row in cursor.fetchall():
cat = row[0]
if '-' in cat:
subs.add(cat.split('-', 1)[1])
self.sub_combo.addItems(sorted(subs)) self.sub_combo.addItems(sorted(subs))
else: else:
cursor = conn.execute("SELECT category FROM fabrics WHERE category LIKE ? OR category = ?", (major + "-%", major)) cursor = conn.execute("SELECT DISTINCT fabric_type FROM fabrics WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''", (major,))
subs = set() subs = [row[0] for row in cursor.fetchall() if row[0]]
for row in cursor.fetchall():
cat = row[0]
if '-' in cat:
subs.add(cat.split('-', 1)[1])
self.sub_combo.addItems(sorted(subs)) self.sub_combo.addItems(sorted(subs))
except: except:
pass pass
@@ -337,7 +329,7 @@ class RawMaterialLibraryDialog(QDialog):
"""加载原料表格数据""" """加载原料表格数据"""
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
query = "SELECT category, model, supplier, color, width, gsm, unit, retail_price, bulk_price FROM fabrics" query = "SELECT category, fabric_type, model, supplier, color, width, gsm, unit, retail_price, bulk_price FROM fabrics"
params = [] params = []
conditions = [] conditions = []
@@ -346,11 +338,11 @@ class RawMaterialLibraryDialog(QDialog):
sub = self.sub_combo.currentText() sub = self.sub_combo.currentText()
if major != "全部类目" and major: if major != "全部类目" and major:
if sub != "全部类型" and sub: if sub != "全部类型" and sub:
conditions.append("category = ?") conditions.append("category = ? AND fabric_type = ?")
params.append(major + "-" + sub) params.append(major)
params.append(sub)
else: else:
conditions.append("(category LIKE ? OR category = ?)") conditions.append("category = ?")
params.append(major + "-%")
params.append(major) params.append(major)
# 供应商过滤 # 供应商过滤
@@ -377,9 +369,9 @@ class RawMaterialLibraryDialog(QDialog):
self.table.setRowCount(len(rows)) self.table.setRowCount(len(rows))
self.table.clearContents() self.table.clearContents()
for row_idx, (category, model, supplier, color, width, gsm, unit, retail, bulk) in enumerate(rows): for row_idx, (category, fabric_type, model, supplier, color, width, gsm, unit, retail, bulk) in enumerate(rows):
major = category.split('-', 1)[0] if '-' in category else category major = category or ""
sub = category.split('-', 1)[1] if '-' in category else "" sub = fabric_type or ""
self.table.setItem(row_idx, 0, QTableWidgetItem(major)) self.table.setItem(row_idx, 0, QTableWidgetItem(major))
self.table.setItem(row_idx, 1, QTableWidgetItem(sub)) self.table.setItem(row_idx, 1, QTableWidgetItem(sub))
@@ -433,16 +425,16 @@ class RawMaterialLibraryDialog(QDialog):
"""编辑原料""" """编辑原料"""
try: try:
with self.get_conn() as conn: with self.get_conn() as conn:
cursor = conn.execute("SELECT category, supplier, color, width, gsm, unit, retail_price, bulk_price FROM fabrics WHERE model = ?", (model,)) cursor = conn.execute("SELECT category, fabric_type, supplier, color, width, gsm, unit, retail_price, bulk_price FROM fabrics WHERE model = ?", (model,))
row = cursor.fetchone() row = cursor.fetchone()
if not row: if not row:
QMessageBox.warning(self, "提示", "原料不存在或已被删除") QMessageBox.warning(self, "提示", "原料不存在或已被删除")
return return
category, supplier, color, width, gsm, unit, retail, bulk = row category, fabric_type, supplier, color, width, gsm, unit, retail, bulk = row
major = category.split('-', 1)[0] if '-' in category else category major = category or ""
sub = category.split('-', 1)[1] if '-' in category else "" sub = fabric_type or ""
self.add_major_category.setCurrentText(major) self.add_major_category.setCurrentText(major)
self.add_sub_category.setText(sub) self.add_sub_category.setText(sub)
@@ -493,10 +485,8 @@ class RawMaterialLibraryDialog(QDialog):
if "胸杯" in sub: if "胸杯" in sub:
major = "辅料" major = "辅料"
if major and sub: category = major or ""
category = major + "-" + sub fabric_type = sub or ""
else:
category = sub or major
supplier = self.add_supplier.currentText().strip() supplier = self.add_supplier.currentText().strip()
color = self.add_color.text().strip() color = self.add_color.text().strip()
@@ -506,9 +496,9 @@ class RawMaterialLibraryDialog(QDialog):
with self.get_conn() as conn: with self.get_conn() as conn:
conn.execute(''' conn.execute('''
INSERT OR REPLACE INTO fabrics INSERT OR REPLACE INTO fabrics
(model, category, supplier, color, width, gsm, retail_price, bulk_price, unit, timestamp) (model, category, fabric_type, supplier, color, width, gsm, retail_price, bulk_price, unit, timestamp)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
''', (model, category, supplier, color, ''', (model, category, fabric_type, supplier, color,
self.add_width.value() or None, self.add_gsm.value() or None, self.add_width.value() or None, self.add_gsm.value() or None,
self.add_retail.value() or None, self.add_bulk.value() or None, self.add_retail.value() or None, self.add_bulk.value() or None,
unit, datetime.now().strftime('%Y-%m-%d %H:%M:%S'))) unit, datetime.now().strftime('%Y-%m-%d %H:%M:%S')))
@@ -627,7 +617,77 @@ class RawMaterialLibraryDialog(QDialog):
def clear_remaining(self, model): def clear_remaining(self, model):
"""清零剩余库存""" """清零剩余库存"""
reply = QMessageBox.question(self, "确认清零", f"确定将 {model} 的剩余量清零?\n(此操作仅逻辑清零,不删除历史记录)") reply = QMessageBox.question(
if reply == QMessageBox.Yes: self,
QMessageBox.information(self, "完成", f"{model} 剩余量已清零(视为全部用完)") "确认清零",
f"确定将 {model} 的剩余量清零?"
)
if reply != QMessageBox.Yes:
return
try:
with self.get_conn() as conn:
# 计算当前总入库量和总消耗量
cursor_in = conn.execute(
"SELECT COALESCE(SUM(quantity), 0) FROM fabric_stock_in WHERE model = ?",
(model,)
)
total_in = cursor_in.fetchone()[0] or 0.0
cursor_out = conn.execute(
"SELECT COALESCE(SUM(consume_quantity), 0) FROM fabric_consumption WHERE model = ?",
(model,)
)
total_out = cursor_out.fetchone()[0] or 0.0
remaining = round(float(total_in) - float(total_out), 6)
if remaining <= 0:
QMessageBox.information(self, "提示", f"{model} 当前没有可清零的剩余库存。")
return
# 获取用于记录此次清零的单位:优先使用最近一次入库单位,其次是原料表里的单位,最后默认“米”
unit = ""
cursor_unit = conn.execute(
"SELECT unit FROM fabric_stock_in WHERE model = ? ORDER BY purchase_date DESC LIMIT 1",
(model,)
)
row_unit = cursor_unit.fetchone()
if row_unit and row_unit[0]:
unit = row_unit[0]
else:
cursor_fabric = conn.execute(
"SELECT unit FROM fabrics WHERE model = ?",
(model,)
)
row_fabric = cursor_fabric.fetchone()
if row_fabric and row_fabric[0]:
unit = row_fabric[0]
# 以一条“清零”消耗记录的方式写入fabric_consumption
conn.execute(
"""
INSERT INTO fabric_consumption
(style_number, model, single_usage, quantity_made, loss_rate, consume_quantity, consume_date, unit)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""",
(
"库存清零", # 特殊标记,表示这是一次手工清零操作
model,
None, # 单件用量无意义置为NULL
0, # 生产件数为0
0.0, # 损耗率0
remaining, # 一次性消耗掉当前所有剩余
datetime.now().strftime('%Y-%m-%d'),
unit,
)
)
conn.commit()
QMessageBox.information(
self,
"完成",
f"{model} 剩余量 {remaining:.3f} {unit} 已清零。"
)
self.load_stock_table() self.load_stock_table()
except Exception as e:
QMessageBox.critical(self, "错误", f"清零失败: {str(e)}")