Compare commits
3 Commits
033a1acef3
...
c52d360cbb
| Author | SHA1 | Date | |
|---|---|---|---|
| c52d360cbb | |||
| 76b16df32c | |||
| 58605b1f92 |
47
database.py
47
database.py
@@ -32,6 +32,7 @@ class DatabaseManager:
|
||||
CREATE TABLE IF NOT EXISTS fabrics (
|
||||
model TEXT PRIMARY KEY,
|
||||
category TEXT DEFAULT '未分类',
|
||||
fabric_type TEXT,
|
||||
supplier TEXT,
|
||||
color TEXT,
|
||||
width REAL,
|
||||
@@ -47,6 +48,7 @@ class DatabaseManager:
|
||||
|
||||
# 为fabrics表添加索引
|
||||
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)')
|
||||
|
||||
# 衣服款号表
|
||||
@@ -66,6 +68,7 @@ class DatabaseManager:
|
||||
style_number TEXT,
|
||||
category TEXT,
|
||||
fabric_type TEXT,
|
||||
model TEXT,
|
||||
usage_per_piece REAL,
|
||||
unit TEXT DEFAULT '米',
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -77,12 +80,21 @@ class DatabaseManager:
|
||||
# 为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_category ON garment_materials(category)')
|
||||
conn.execute('CREATE INDEX IF NOT EXISTS idx_garment_materials_model ON garment_materials(model)')
|
||||
|
||||
# 添加新字段(如果不存在)
|
||||
try:
|
||||
conn.execute("ALTER TABLE garment_materials ADD COLUMN fabric_type TEXT")
|
||||
except:
|
||||
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:
|
||||
conn.execute("ALTER TABLE fabrics ADD COLUMN created_at DATETIME DEFAULT CURRENT_TIMESTAMP")
|
||||
except:
|
||||
@@ -131,6 +143,21 @@ class DatabaseManager:
|
||||
conn.execute("ALTER TABLE fabric_consumption ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP")
|
||||
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:
|
||||
pass
|
||||
|
||||
# 管理员设置表
|
||||
conn.execute('''
|
||||
@@ -246,14 +273,10 @@ def get_fabric_categories(db_path):
|
||||
try:
|
||||
with get_db_connection(db_path) as conn:
|
||||
cursor = conn.execute("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN category LIKE '%-%' THEN SUBSTR(category, 1, INSTR(category, '-') - 1)
|
||||
ELSE category
|
||||
END as major_category
|
||||
SELECT DISTINCT category
|
||||
FROM fabrics
|
||||
WHERE category IS NOT NULL AND category != ''
|
||||
ORDER BY major_category
|
||||
ORDER BY category
|
||||
""")
|
||||
categories = set()
|
||||
for row in cursor.fetchall():
|
||||
@@ -272,19 +295,15 @@ def get_fabric_types_by_category(db_path, category):
|
||||
try:
|
||||
with get_db_connection(db_path) as conn:
|
||||
cursor = conn.execute("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
|
||||
ELSE '默认类型'
|
||||
END as fabric_type
|
||||
SELECT DISTINCT fabric_type
|
||||
FROM fabrics
|
||||
WHERE category LIKE ? OR category = ?
|
||||
WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''
|
||||
ORDER BY fabric_type
|
||||
""", (f"{category}-%", category))
|
||||
""", (category,))
|
||||
|
||||
types = []
|
||||
for row in cursor.fetchall():
|
||||
if row[0] and row[0] != '默认类型':
|
||||
if row[0] and row[0].strip():
|
||||
types.append(row[0])
|
||||
return types
|
||||
except:
|
||||
|
||||
Binary file not shown.
@@ -86,45 +86,55 @@ class FabricManager(QMainWindow):
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.execute('''
|
||||
SELECT category, fabric_type, usage_per_piece, unit
|
||||
SELECT model, category, fabric_type, usage_per_piece, unit
|
||||
FROM garment_materials
|
||||
WHERE style_number = ?
|
||||
''', (style_number,))
|
||||
rows = cursor.fetchall()
|
||||
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:
|
||||
continue
|
||||
|
||||
# 获取该原料在入库时使用的单位
|
||||
|
||||
# 优先使用精确原料型号(model);如无型号则退回到分类名称(兼容旧数据)
|
||||
raw_identifier = model if model else category
|
||||
|
||||
# 获取该原料在入库时使用的单位(最近一次入库)
|
||||
stock_cursor = conn.execute('''
|
||||
SELECT unit FROM fabric_stock_in
|
||||
WHERE model = ?
|
||||
ORDER BY purchase_date DESC
|
||||
LIMIT 1
|
||||
''', (category,))
|
||||
''', (raw_identifier,))
|
||||
stock_unit_row = stock_cursor.fetchone()
|
||||
|
||||
# 如果有入库记录,使用入库单位;否则使用原来的单位
|
||||
|
||||
total_usage = usage_per_piece * quantity * (1 + loss_rate)
|
||||
|
||||
# 如果有入库记录,则按入库单位扣减库存;必要时进行单位换算
|
||||
if stock_unit_row:
|
||||
stock_unit = stock_unit_row[0]
|
||||
# 如果单位不同,需要转换
|
||||
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
|
||||
else:
|
||||
consume_qty = usage_per_piece * quantity * (1 + loss_rate)
|
||||
consume_qty = total_usage
|
||||
final_unit = unit
|
||||
else:
|
||||
# 没有入库记录,使用原单位
|
||||
consume_qty = usage_per_piece * quantity * (1 + loss_rate)
|
||||
# 没有入库记录,只能按原单位记录消耗
|
||||
consume_qty = total_usage
|
||||
final_unit = unit
|
||||
|
||||
|
||||
conn.execute('''
|
||||
INSERT INTO fabric_consumption
|
||||
(style_number, model, single_usage, quantity_made, loss_rate, consume_quantity, consume_date, unit)
|
||||
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
|
||||
conn.commit()
|
||||
if inserted > 0:
|
||||
@@ -177,12 +187,17 @@ class FabricManager(QMainWindow):
|
||||
text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n"
|
||||
try:
|
||||
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,))
|
||||
for category, fabric_type, usage, unit in cursor.fetchall():
|
||||
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, model, usage, unit in cursor.fetchall():
|
||||
if usage:
|
||||
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"
|
||||
except Exception as e:
|
||||
text += "计算失败: " + str(e)
|
||||
@@ -332,6 +347,7 @@ class FabricManager(QMainWindow):
|
||||
CREATE TABLE IF NOT EXISTS fabrics (
|
||||
model TEXT PRIMARY KEY,
|
||||
category TEXT DEFAULT '未分类',
|
||||
fabric_type TEXT,
|
||||
supplier TEXT,
|
||||
color TEXT,
|
||||
width REAL,
|
||||
@@ -356,6 +372,7 @@ class FabricManager(QMainWindow):
|
||||
style_number TEXT,
|
||||
category TEXT,
|
||||
fabric_type TEXT,
|
||||
model TEXT,
|
||||
usage_per_piece REAL,
|
||||
unit TEXT DEFAULT '米'
|
||||
)
|
||||
@@ -364,6 +381,30 @@ class FabricManager(QMainWindow):
|
||||
# 添加fabric_type列(如果不存在)
|
||||
try:
|
||||
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:
|
||||
pass # 列已存在
|
||||
|
||||
|
||||
@@ -10,107 +10,68 @@ from PyQt5.QtWidgets import (
|
||||
QPushButton, QComboBox, QTableWidget, QTableWidgetItem, QHeaderView,
|
||||
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 database import get_db_connection
|
||||
|
||||
|
||||
class SearchableComboBox(QComboBox):
|
||||
"""支持模糊搜索的下拉框"""
|
||||
"""支持模糊搜索的下拉框 - 基于 QSortFilterProxyModel 和 QCompleter"""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
super(SearchableComboBox, self).__init__(parent)
|
||||
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setEditable(True)
|
||||
self.setInsertPolicy(QComboBox.NoInsert)
|
||||
|
||||
# 存储所有选项
|
||||
self.all_items = []
|
||||
self.all_data = []
|
||||
self.is_filtering = False
|
||||
|
||||
# 设置自动完成
|
||||
self.completer = QCompleter(self)
|
||||
self.completer.setCompletionMode(QCompleter.PopupCompletion)
|
||||
self.completer.setCaseSensitivity(Qt.CaseInsensitive)
|
||||
self.completer.setFilterMode(Qt.MatchContains)
|
||||
self.setCompleter(self.completer)
|
||||
|
||||
# 连接信号
|
||||
self.lineEdit().textChanged.connect(self.on_text_changed)
|
||||
|
||||
def addItem(self, text, userData=None):
|
||||
"""添加选项"""
|
||||
# 临时断开信号连接,防止textChanged触发on_text_changed
|
||||
self.lineEdit().textChanged.disconnect()
|
||||
super().addItem(text, userData)
|
||||
if text not in self.all_items:
|
||||
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):
|
||||
"""批量添加选项"""
|
||||
for text in texts:
|
||||
self.addItem(text)
|
||||
|
||||
def clear(self):
|
||||
"""清空所有选项"""
|
||||
if not self.is_filtering:
|
||||
super().clear()
|
||||
self.all_items.clear()
|
||||
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()
|
||||
|
||||
# 添加过滤模型来过滤匹配项
|
||||
self.pFilterModel = QSortFilterProxyModel(self)
|
||||
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
|
||||
self.pFilterModel.setSourceModel(self.model())
|
||||
|
||||
# 添加自动完成器,使用过滤模型
|
||||
self.completer = QCompleter(self.pFilterModel, self)
|
||||
# 始终显示所有(过滤后的)完成项
|
||||
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
|
||||
self.setCompleter(self.completer)
|
||||
|
||||
# 连接信号
|
||||
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
|
||||
self.completer.activated.connect(self.on_completer_activated)
|
||||
|
||||
# 当从自动完成器中选择项时,从组合框中选择对应的项
|
||||
def on_completer_activated(self, text):
|
||||
if text:
|
||||
index = self.findText(text)
|
||||
self.setCurrentIndex(index)
|
||||
self.activated[str].emit(self.itemText(index))
|
||||
|
||||
# 当模型改变时,同时更新过滤器和自动完成器的模型
|
||||
def setModel(self, model):
|
||||
super(SearchableComboBox, self).setModel(model)
|
||||
self.pFilterModel.setSourceModel(model)
|
||||
self.completer.setModel(self.pFilterModel)
|
||||
|
||||
# 当模型列改变时,同时更新过滤器和自动完成器的模型列
|
||||
def setModelColumn(self, column):
|
||||
self.completer.setCompletionColumn(column)
|
||||
self.pFilterModel.setFilterKeyColumn(column)
|
||||
super(SearchableComboBox, self).setModelColumn(column)
|
||||
|
||||
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):
|
||||
"""服装库管理对话框"""
|
||||
@@ -355,40 +316,12 @@ class GarmentEditDialog(QDialog):
|
||||
"""加载材料列表"""
|
||||
try:
|
||||
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,))
|
||||
for category, fabric_type, usage, unit in cursor.fetchall():
|
||||
display_category = ""
|
||||
display_type = ""
|
||||
display_model = ""
|
||||
|
||||
# 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
|
||||
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, model, usage, unit in cursor.fetchall():
|
||||
# 直接使用数据库中的三个字段
|
||||
display_category = category or ""
|
||||
display_type = fabric_type or ""
|
||||
display_model = model or ""
|
||||
|
||||
self.add_material_row(display_category, display_type, usage or 0, unit or "米", display_model)
|
||||
except Exception as e:
|
||||
@@ -403,37 +336,30 @@ class GarmentEditDialog(QDialog):
|
||||
|
||||
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()
|
||||
self.material_table.insertRow(row)
|
||||
|
||||
# 列0: 类目下拉框
|
||||
cat_combo = QComboBox()
|
||||
cat_combo.setEditable(True)
|
||||
cat_combo.setEditable(False)
|
||||
# 最后添加自定义选项
|
||||
cat_combo.addItem("—— 自定义类目 ——")
|
||||
|
||||
# 先添加所有类目选项
|
||||
try:
|
||||
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 as major_category
|
||||
SELECT DISTINCT category
|
||||
FROM fabrics
|
||||
WHERE category IS NOT NULL AND category != ''
|
||||
ORDER BY major_category
|
||||
ORDER BY category
|
||||
""")
|
||||
categories = set()
|
||||
for cat_row in cursor.fetchall():
|
||||
if cat_row[0] and cat_row[0].strip():
|
||||
categories.add(cat_row[0])
|
||||
|
||||
# 添加默认类目
|
||||
categories.update(["布料", "辅料", "其他"])
|
||||
|
||||
for cat in sorted(categories):
|
||||
cat_combo.addItem(cat)
|
||||
except:
|
||||
@@ -445,79 +371,62 @@ class GarmentEditDialog(QDialog):
|
||||
if category:
|
||||
cat_combo.setCurrentText(category)
|
||||
else:
|
||||
# 如果没有指定类目,默认选择第一个实际类目而不是"自定义类目"
|
||||
if cat_combo.count() > 1:
|
||||
cat_combo.setCurrentIndex(0)
|
||||
# 如果没有指定类目,默认选择"—— 自定义类目 ——"(索引0)
|
||||
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.currentTextChanged.connect(lambda text, r=row: self.on_category_changed(text, r))
|
||||
self.material_table.setCellWidget(row, 0, cat_combo)
|
||||
|
||||
# 列1: 类型下拉框
|
||||
type_combo = QComboBox()
|
||||
type_combo.setEditable(True)
|
||||
|
||||
type_combo.setEditable(False)
|
||||
# 最后添加选择提示
|
||||
type_combo.addItem("—— 选择类型 ——")
|
||||
# 先添加所有类型选项
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.execute("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
|
||||
ELSE '默认类型'
|
||||
END as fabric_type
|
||||
SELECT DISTINCT fabric_type
|
||||
FROM fabrics
|
||||
WHERE category IS NOT NULL AND category != ''
|
||||
WHERE fabric_type IS NOT NULL AND fabric_type != ''
|
||||
ORDER BY fabric_type
|
||||
""")
|
||||
|
||||
types = cursor.fetchall()
|
||||
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])
|
||||
except:
|
||||
pass
|
||||
|
||||
# 最后添加选择提示
|
||||
type_combo.addItem("—— 选择类型 ——")
|
||||
|
||||
if fabric_type:
|
||||
type_combo.setCurrentText(fabric_type)
|
||||
else:
|
||||
# 如果没有指定类型,默认选择第一个实际类型而不是"选择类型"
|
||||
if type_combo.count() > 1:
|
||||
type_combo.setCurrentIndex(0)
|
||||
# 如果没有指定类型,默认选择"—— 选择类型 ——"(索引0)
|
||||
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.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r))
|
||||
self.material_table.setCellWidget(row, 1, type_combo)
|
||||
|
||||
# 列2: 型号下拉框(支持模糊搜索)
|
||||
model_combo = SearchableComboBox()
|
||||
model_combo.addItem("—— 选择型号 ——")
|
||||
|
||||
# 初始化时加载所有型号
|
||||
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))
|
||||
# 先将下拉框添加到表格中,这样update_model_combo_range才能获取到类目和类型
|
||||
self.material_table.setCellWidget(row, 2, model_combo)
|
||||
|
||||
# 初始化时根据类目和类型加载对应的型号
|
||||
self.update_model_combo_range(model_combo, row)
|
||||
|
||||
# 列3: 单件用量
|
||||
usage_spin = QDoubleSpinBox()
|
||||
@@ -539,38 +448,121 @@ class GarmentEditDialog(QDialog):
|
||||
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() == "—— 自定义类目 ——":
|
||||
self.on_type_changed("—— 选择类型 ——", row)
|
||||
# if cat_combo.currentText() == "—— 自定义类目 ——":
|
||||
# self.on_type_changed("—— 选择类型 ——", row)
|
||||
|
||||
# 如果有指定的型号,需要在初始化完成后设置
|
||||
if model:
|
||||
# 先设置类型(如果有的话)
|
||||
if fabric_type:
|
||||
type_combo.setCurrentText(fabric_type)
|
||||
self.on_type_changed(fabric_type, row)
|
||||
# if model:
|
||||
# # 先设置类型(如果有的话)
|
||||
# if fabric_type:
|
||||
# type_combo.setCurrentText(fabric_type)
|
||||
# self.on_type_changed(fabric_type, row)
|
||||
|
||||
# 然后设置型号 - 使用SearchableComboBox的setCurrentText方法
|
||||
model_combo = self.material_table.cellWidget(row, 2)
|
||||
if isinstance(model_combo, SearchableComboBox):
|
||||
# 确保型号在选项列表中
|
||||
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
|
||||
# # 然后设置型号
|
||||
# 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
|
||||
""")
|
||||
|
||||
# 如果没找到,直接设置文本(SearchableComboBox支持)
|
||||
if not found:
|
||||
model_combo.setCurrentText(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):
|
||||
model_combo.setDefaultText("—— 选择型号 ——")
|
||||
else:
|
||||
model_combo.setCurrentIndex(0)
|
||||
except Exception as e:
|
||||
pass
|
||||
finally:
|
||||
if line_edit:
|
||||
line_edit.blockSignals(False)
|
||||
model_combo.blockSignals(False)
|
||||
|
||||
def on_category_changed(self, category_text, row):
|
||||
"""当类目改变时,更新类型下拉框"""
|
||||
print("on_category_changed", category_text, row)
|
||||
type_combo = self.material_table.cellWidget(row, 1)
|
||||
model_combo = self.material_table.cellWidget(row, 2)
|
||||
|
||||
@@ -578,146 +570,132 @@ class GarmentEditDialog(QDialog):
|
||||
type_combo.clear()
|
||||
type_combo.addItem("—— 选择类型 ——")
|
||||
|
||||
# 重新初始化型号下拉框,显示所有型号
|
||||
model_combo.clear()
|
||||
model_combo.addItem("—— 选择型号 ——")
|
||||
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
# 加载所有类型
|
||||
cursor = conn.execute("""
|
||||
SELECT DISTINCT
|
||||
CASE
|
||||
WHEN category LIKE '%-%' THEN SUBSTR(category, INSTR(category, '-') + 1)
|
||||
ELSE '默认类型'
|
||||
END as fabric_type
|
||||
FROM fabrics
|
||||
WHERE category IS NOT NULL AND category != ''
|
||||
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
|
||||
SELECT DISTINCT fabric_type
|
||||
FROM fabrics
|
||||
WHERE category LIKE ? OR category = ?
|
||||
WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''
|
||||
ORDER BY fabric_type
|
||||
""", (f"{category_text}-%", category_text))
|
||||
""", (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
|
||||
""")
|
||||
|
||||
types = cursor.fetchall()
|
||||
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.currentTextChanged.connect(lambda text, r=row: self.on_type_changed(text, r))
|
||||
|
||||
# 加载所有型号到型号下拉框
|
||||
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)
|
||||
|
||||
# 确保默认选中第一项("—— 选择型号 ——")
|
||||
model_combo.setCurrentIndex(0)
|
||||
# 更新型号下拉框的搜索范围
|
||||
self.update_model_combo_range(model_combo, row)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
def on_type_changed(self, type_text, row):
|
||||
"""当类型改变时,更新型号下拉框"""
|
||||
"""当类型改变时,更新类目和型号下拉框"""
|
||||
print("on_type_changed", type_text, row)
|
||||
cat_combo = self.material_table.cellWidget(row, 0)
|
||||
model_combo = self.material_table.cellWidget(row, 2)
|
||||
|
||||
# 重新初始化型号下拉框,显示所有型号
|
||||
if hasattr(model_combo, 'clear'):
|
||||
model_combo.clear()
|
||||
model_combo.addItem("—— 选择型号 ——")
|
||||
if not model_combo:
|
||||
return
|
||||
|
||||
# 始终显示所有型号,不进行过滤
|
||||
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)
|
||||
|
||||
# 确保默认选中第一项("—— 选择型号 ——")
|
||||
model_combo.setCurrentIndex(0)
|
||||
except Exception as e:
|
||||
pass
|
||||
# 如果选择了具体类型,自动选中该类型对应的类目
|
||||
if cat_combo and type_text and type_text != "—— 选择类型 ——":
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
# 查询该类型对应的类目
|
||||
cursor = conn.execute("""
|
||||
SELECT DISTINCT category
|
||||
FROM fabrics
|
||||
WHERE fabric_type = ? AND category IS NOT NULL AND category != ''
|
||||
ORDER BY category
|
||||
LIMIT 1
|
||||
""", (type_text,))
|
||||
row_db = cursor.fetchone()
|
||||
if row_db and row_db[0]:
|
||||
category = row_db[0].strip()
|
||||
# 在类目下拉框中查找并选中该类目
|
||||
index = cat_combo.findText(category)
|
||||
if index >= 0:
|
||||
cat_combo.blockSignals(True)
|
||||
cat_combo.setCurrentIndex(index)
|
||||
cat_combo.blockSignals(False)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
# 更新型号下拉框的搜索范围
|
||||
self.update_model_combo_range(model_combo, row)
|
||||
|
||||
def on_model_selected(self, model_text, row):
|
||||
"""当型号选择时,自动设置单位并填充类目和类型"""
|
||||
if not model_text or model_text == "—— 选择型号 ——":
|
||||
return
|
||||
|
||||
print("on_model_selected", model_text, row)
|
||||
# 先获取所有需要的控件
|
||||
cat_combo = self.material_table.cellWidget(row, 0)
|
||||
type_combo = self.material_table.cellWidget(row, 1)
|
||||
model_combo = self.material_table.cellWidget(row, 2)
|
||||
unit_combo = self.material_table.cellWidget(row, 4)
|
||||
|
||||
# 获取选中项的数据
|
||||
current_index = model_combo.currentIndex()
|
||||
if current_index > 0:
|
||||
model = model_combo.itemData(current_index)
|
||||
if model:
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.execute("SELECT category, unit FROM fabrics WHERE model = ?", (model,))
|
||||
row_db = cursor.fetchone()
|
||||
if row_db:
|
||||
category, unit = row_db
|
||||
|
||||
# 自动填充单位
|
||||
if unit:
|
||||
unit_combo.setCurrentText(unit)
|
||||
|
||||
# 自动填充类目和类型
|
||||
if category:
|
||||
# 解析类目信息,可能是"类目-类型"格式或单独的类目
|
||||
if '-' in category:
|
||||
parts = category.split('-', 1)
|
||||
cat_text = parts[0]
|
||||
type_text = parts[1] if len(parts) > 1 else ""
|
||||
|
||||
# 设置类目
|
||||
cat_combo.setCurrentText(cat_text)
|
||||
|
||||
# 更新类型下拉框选项
|
||||
self.on_category_changed(cat_text, row)
|
||||
|
||||
# 设置类型
|
||||
if type_text:
|
||||
type_combo.setCurrentText(type_text)
|
||||
else:
|
||||
# 只有类目,没有类型
|
||||
cat_combo.setCurrentText(category)
|
||||
self.on_category_changed(category, row)
|
||||
except:
|
||||
pass
|
||||
if not model_text or model_text == "—— 选择型号 ——":
|
||||
# 空选择,不做联动
|
||||
return
|
||||
|
||||
# 从显示文本中解析真实型号(例如 "M001-红" -> "M001")
|
||||
display_text = model_text.strip()
|
||||
base_model = display_text.split("-", 1)[0] if "-" in display_text else display_text
|
||||
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.execute(
|
||||
"SELECT category, fabric_type, unit FROM fabrics WHERE model = ?",
|
||||
(base_model,)
|
||||
)
|
||||
row_db = cursor.fetchone()
|
||||
if row_db:
|
||||
category, fabric_type, unit = row_db
|
||||
|
||||
# 自动填充单位
|
||||
if unit:
|
||||
unit_combo.setCurrentText(unit)
|
||||
|
||||
# 自动填充类目和类型,阻止信号以避免触发默认更新逻辑
|
||||
if category:
|
||||
# 阻止类目、类型和型号的信号,避免触发默认更新逻辑
|
||||
cat_combo.blockSignals(True)
|
||||
type_combo.blockSignals(True)
|
||||
model_combo.blockSignals(True)
|
||||
|
||||
# 设置类目
|
||||
cat_combo.setCurrentText(category)
|
||||
|
||||
# 更新类型下拉框选项(直接调用,不会触发信号因为已经阻止了)
|
||||
self.on_category_changed(category, row)
|
||||
|
||||
# 重新阻止信号(因为on_category_changed内部可能恢复了信号)
|
||||
model_combo.blockSignals(True)
|
||||
|
||||
# 设置类型
|
||||
if fabric_type:
|
||||
type_combo.setCurrentText(fabric_type)
|
||||
|
||||
# 恢复信号
|
||||
cat_combo.blockSignals(False)
|
||||
type_combo.blockSignals(False)
|
||||
model_combo.blockSignals(False)
|
||||
except:
|
||||
pass
|
||||
|
||||
def save_garment(self):
|
||||
"""保存服装"""
|
||||
@@ -764,11 +742,9 @@ class GarmentEditDialog(QDialog):
|
||||
usage = usage_widget.value()
|
||||
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, usage_per_piece, unit) VALUES (?, ?, ?, ?, ?)",
|
||||
(style_number, material_identifier, fabric_type, usage, unit))
|
||||
# 分别存储类目、类型和型号到对应字段
|
||||
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.commit()
|
||||
QMessageBox.information(self, "成功", "保存完成")
|
||||
|
||||
13
main.py
13
main.py
@@ -335,12 +335,17 @@ class FabricManager(QMainWindow):
|
||||
text = f"款号: {style_number}\n生产件数: {qty}\n损耗率: {self.loss_input.value()}%\n\n"
|
||||
try:
|
||||
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,))
|
||||
for category, fabric_type, usage, unit in cursor.fetchall():
|
||||
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, model, usage, unit in cursor.fetchall():
|
||||
if usage:
|
||||
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"
|
||||
except Exception as e:
|
||||
text += "计算失败: " + str(e)
|
||||
|
||||
@@ -76,17 +76,22 @@ class PurchaseOrderDialog(QDialog):
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
cursor = conn.execute('''
|
||||
SELECT category, fabric_type, usage_per_piece, unit
|
||||
SELECT category, fabric_type, model, usage_per_piece, unit
|
||||
FROM garment_materials
|
||||
WHERE style_number = ? AND usage_per_piece > 0
|
||||
ORDER BY id
|
||||
''', (self.style_number,))
|
||||
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)
|
||||
# 显示材料名称(如果有类型则显示类目-类型,否则只显示类目)
|
||||
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" 单件用量:{usage_per_piece:.3f} {unit}\n"
|
||||
text += f" 总需采购:{total_usage:.3f} {unit}\n\n"
|
||||
|
||||
@@ -246,7 +246,7 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
"""加载主类目"""
|
||||
try:
|
||||
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.update({"布料", "辅料", "其他"})
|
||||
|
||||
@@ -263,7 +263,7 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
"""加载添加界面的主类目"""
|
||||
try:
|
||||
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.update({"布料", "辅料", "其他"})
|
||||
|
||||
@@ -292,20 +292,12 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
try:
|
||||
with self.get_conn() as conn:
|
||||
if major in ("全部类目", ""):
|
||||
cursor = conn.execute("SELECT DISTINCT category FROM fabrics WHERE category LIKE '%-%'")
|
||||
subs = set()
|
||||
for row in cursor.fetchall():
|
||||
cat = row[0]
|
||||
if '-' in cat:
|
||||
subs.add(cat.split('-', 1)[1])
|
||||
cursor = conn.execute("SELECT DISTINCT fabric_type FROM fabrics WHERE fabric_type IS NOT NULL AND fabric_type != ''")
|
||||
subs = [row[0] for row in cursor.fetchall() if row[0]]
|
||||
self.sub_combo.addItems(sorted(subs))
|
||||
else:
|
||||
cursor = conn.execute("SELECT category FROM fabrics WHERE category LIKE ? OR category = ?", (major + "-%", major))
|
||||
subs = set()
|
||||
for row in cursor.fetchall():
|
||||
cat = row[0]
|
||||
if '-' in cat:
|
||||
subs.add(cat.split('-', 1)[1])
|
||||
cursor = conn.execute("SELECT DISTINCT fabric_type FROM fabrics WHERE category = ? AND fabric_type IS NOT NULL AND fabric_type != ''", (major,))
|
||||
subs = [row[0] for row in cursor.fetchall() if row[0]]
|
||||
self.sub_combo.addItems(sorted(subs))
|
||||
except:
|
||||
pass
|
||||
@@ -337,7 +329,7 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
"""加载原料表格数据"""
|
||||
try:
|
||||
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 = []
|
||||
conditions = []
|
||||
|
||||
@@ -346,11 +338,11 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
sub = self.sub_combo.currentText()
|
||||
if major != "全部类目" and major:
|
||||
if sub != "全部类型" and sub:
|
||||
conditions.append("category = ?")
|
||||
params.append(major + "-" + sub)
|
||||
conditions.append("category = ? AND fabric_type = ?")
|
||||
params.append(major)
|
||||
params.append(sub)
|
||||
else:
|
||||
conditions.append("(category LIKE ? OR category = ?)")
|
||||
params.append(major + "-%")
|
||||
conditions.append("category = ?")
|
||||
params.append(major)
|
||||
|
||||
# 供应商过滤
|
||||
@@ -377,9 +369,9 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
self.table.setRowCount(len(rows))
|
||||
self.table.clearContents()
|
||||
|
||||
for row_idx, (category, model, supplier, color, width, gsm, unit, retail, bulk) in enumerate(rows):
|
||||
major = category.split('-', 1)[0] if '-' in category else category
|
||||
sub = category.split('-', 1)[1] if '-' in category else ""
|
||||
for row_idx, (category, fabric_type, model, supplier, color, width, gsm, unit, retail, bulk) in enumerate(rows):
|
||||
major = category or ""
|
||||
sub = fabric_type or ""
|
||||
|
||||
self.table.setItem(row_idx, 0, QTableWidgetItem(major))
|
||||
self.table.setItem(row_idx, 1, QTableWidgetItem(sub))
|
||||
@@ -433,16 +425,16 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
"""编辑原料"""
|
||||
try:
|
||||
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()
|
||||
if not row:
|
||||
QMessageBox.warning(self, "提示", "原料不存在或已被删除")
|
||||
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
|
||||
sub = category.split('-', 1)[1] if '-' in category else ""
|
||||
major = category or ""
|
||||
sub = fabric_type or ""
|
||||
|
||||
self.add_major_category.setCurrentText(major)
|
||||
self.add_sub_category.setText(sub)
|
||||
@@ -493,10 +485,8 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
if "胸杯" in sub:
|
||||
major = "辅料"
|
||||
|
||||
if major and sub:
|
||||
category = major + "-" + sub
|
||||
else:
|
||||
category = sub or major
|
||||
category = major or ""
|
||||
fabric_type = sub or ""
|
||||
|
||||
supplier = self.add_supplier.currentText().strip()
|
||||
color = self.add_color.text().strip()
|
||||
@@ -506,9 +496,9 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
with self.get_conn() as conn:
|
||||
conn.execute('''
|
||||
INSERT OR REPLACE INTO fabrics
|
||||
(model, category, supplier, color, width, gsm, retail_price, bulk_price, unit, timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (model, category, supplier, color,
|
||||
(model, category, fabric_type, supplier, color, width, gsm, retail_price, bulk_price, unit, timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', (model, category, fabric_type, supplier, color,
|
||||
self.add_width.value() or None, self.add_gsm.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')))
|
||||
@@ -627,7 +617,77 @@ class RawMaterialLibraryDialog(QDialog):
|
||||
|
||||
def clear_remaining(self, model):
|
||||
"""清零剩余库存"""
|
||||
reply = QMessageBox.question(self, "确认清零", f"确定将 {model} 的剩余量清零?\n(此操作仅逻辑清零,不删除历史记录)")
|
||||
if reply == QMessageBox.Yes:
|
||||
QMessageBox.information(self, "完成", f"{model} 剩余量已清零(视为全部用完)")
|
||||
self.load_stock_table()
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"确认清零",
|
||||
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()
|
||||
except Exception as e:
|
||||
QMessageBox.critical(self, "错误", f"清零失败: {str(e)}")
|
||||
Reference in New Issue
Block a user