898 lines
38 KiB
Python
898 lines
38 KiB
Python
"""
|
||
服装管理模块 - 处理服装款式和材料用量管理
|
||
"""
|
||
|
||
import os
|
||
from datetime import datetime
|
||
from PIL import Image
|
||
from PyQt5.QtWidgets import (
|
||
QDialog, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QLineEdit,
|
||
QPushButton, QComboBox, QTableWidget, QTableWidgetItem, QHeaderView,
|
||
QMessageBox, QFileDialog, QDoubleSpinBox, QWidget, QCompleter
|
||
)
|
||
from PyQt5.QtCore import Qt, QStringListModel, QTimer
|
||
from PyQt5.QtGui import QPixmap
|
||
from database import get_db_connection
|
||
|
||
|
||
class SearchableComboBox(QComboBox):
|
||
"""支持模糊搜索的下拉框"""
|
||
|
||
def __init__(self, parent=None):
|
||
super().__init__(parent)
|
||
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
|
||
try:
|
||
self.lineEdit().textChanged.disconnect()
|
||
except TypeError:
|
||
# 信号未连接或已被断开,忽略错误
|
||
pass
|
||
super().addItem(text, userData)
|
||
if text not in self.all_items:
|
||
self.all_items.append(text)
|
||
self.all_data.append(userData)
|
||
self.update_completer()
|
||
# 重新连接信号
|
||
try:
|
||
self.lineEdit().textChanged.connect(self.on_text_changed)
|
||
except:
|
||
# 如果连接失败,忽略错误
|
||
pass
|
||
|
||
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
|
||
try:
|
||
self.lineEdit().textChanged.disconnect()
|
||
except TypeError:
|
||
# 信号未连接或已被断开,忽略错误
|
||
pass
|
||
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
|
||
# 重新连接信号
|
||
try:
|
||
self.lineEdit().textChanged.connect(self.on_text_changed)
|
||
except:
|
||
# 如果连接失败,忽略错误
|
||
pass
|
||
# # 确保当前索引设置为0(第一项)
|
||
# if self.count() > 0:
|
||
# super().setCurrentIndex(0)
|
||
|
||
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):
|
||
"""设置默认文本"""
|
||
# 临时断开信号连接,防止textChanged触发on_text_changed
|
||
try:
|
||
self.lineEdit().textChanged.disconnect()
|
||
except TypeError:
|
||
# 信号未连接或已被断开,忽略错误
|
||
pass
|
||
self.lineEdit().setText(text)
|
||
self.update_completer()
|
||
# 重新连接信号
|
||
try:
|
||
self.lineEdit().textChanged.connect(self.on_text_changed)
|
||
except:
|
||
# 如果连接失败,忽略错误
|
||
pass
|
||
|
||
class GarmentLibraryDialog(QDialog):
|
||
"""服装库管理对话框"""
|
||
|
||
def __init__(self, db_path):
|
||
super().__init__()
|
||
self.db_path = db_path
|
||
self.setWindowTitle("衣服款号管理")
|
||
self.resize(1300, 750)
|
||
|
||
self.setup_ui()
|
||
self.load_garments()
|
||
|
||
def setup_ui(self):
|
||
"""设置用户界面"""
|
||
layout = QVBoxLayout(self)
|
||
|
||
# 操作按钮区域
|
||
op_layout = QHBoxLayout()
|
||
op_layout.addWidget(QLabel("搜索款号:"))
|
||
self.search_input = QLineEdit()
|
||
self.search_input.textChanged.connect(self.load_garments)
|
||
op_layout.addWidget(self.search_input)
|
||
|
||
add_btn = QPushButton("新增/编辑款号")
|
||
add_btn.clicked.connect(self.edit_garment)
|
||
op_layout.addWidget(add_btn)
|
||
|
||
del_btn = QPushButton("删除选中款号")
|
||
del_btn.clicked.connect(self.delete_garment)
|
||
op_layout.addWidget(del_btn)
|
||
|
||
refresh_btn = QPushButton("刷新")
|
||
refresh_btn.clicked.connect(self.load_garments)
|
||
op_layout.addWidget(refresh_btn)
|
||
|
||
layout.addLayout(op_layout)
|
||
|
||
# 服装表格
|
||
self.garment_table = QTableWidget()
|
||
self.garment_table.setColumnCount(3)
|
||
self.garment_table.setHorizontalHeaderLabels(["款号", "类目数量", "款式图预览"])
|
||
self.garment_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||
self.garment_table.itemDoubleClicked.connect(self.edit_garment_from_table)
|
||
layout.addWidget(self.garment_table)
|
||
|
||
def get_conn(self):
|
||
"""获取数据库连接"""
|
||
return get_db_connection(self.db_path)
|
||
|
||
def load_garments(self):
|
||
"""加载服装列表"""
|
||
keyword = self.search_input.text().strip()
|
||
try:
|
||
with self.get_conn() as conn:
|
||
query = "SELECT style_number, image_path FROM garments"
|
||
params = []
|
||
if keyword:
|
||
query += " WHERE style_number LIKE ?"
|
||
params = ["%" + keyword + "%"]
|
||
query += " ORDER BY style_number"
|
||
|
||
cursor = conn.execute(query, params)
|
||
rows = cursor.fetchall()
|
||
|
||
self.garment_table.setRowCount(len(rows))
|
||
for i in range(len(rows)):
|
||
self.garment_table.setRowHeight(i, 140)
|
||
|
||
for row_idx, (style_number, image_path) in enumerate(rows):
|
||
self.garment_table.setItem(row_idx, 0, QTableWidgetItem(style_number))
|
||
|
||
# 查询材料数量
|
||
with self.get_conn() as conn:
|
||
cursor2 = conn.execute("SELECT COUNT(*) FROM garment_materials WHERE style_number = ?", (style_number,))
|
||
count = cursor2.fetchone()[0]
|
||
self.garment_table.setItem(row_idx, 1, QTableWidgetItem(str(count)))
|
||
|
||
# 显示图片预览
|
||
image_item = QTableWidgetItem()
|
||
image_item.setTextAlignment(Qt.AlignCenter)
|
||
|
||
if image_path and os.path.exists(image_path):
|
||
try:
|
||
pixmap = QPixmap(image_path).scaled(130, 130, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||
image_item.setData(Qt.DecorationRole, pixmap)
|
||
except:
|
||
image_item.setText("加载失败")
|
||
else:
|
||
image_item.setText("无图片")
|
||
|
||
self.garment_table.setItem(row_idx, 2, image_item)
|
||
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "加载失败", "错误: " + str(e))
|
||
|
||
def edit_garment_from_table(self):
|
||
"""从表格编辑服装"""
|
||
row = self.garment_table.currentRow()
|
||
if row >= 0:
|
||
style_number = self.garment_table.item(row, 0).text()
|
||
self.edit_garment(style_number)
|
||
|
||
def edit_garment(self, style_number=None):
|
||
"""编辑服装"""
|
||
dialog = GarmentEditDialog(self.db_path, style_number)
|
||
if dialog.exec_():
|
||
self.load_garments()
|
||
|
||
def delete_garment(self):
|
||
"""删除服装"""
|
||
row = self.garment_table.currentRow()
|
||
if row < 0:
|
||
QMessageBox.warning(self, "提示", "请先选中一款号")
|
||
return
|
||
style_number = self.garment_table.item(row, 0).text()
|
||
reply = QMessageBox.question(self, "确认", f"删除款号 '{style_number}' 及其所有信息?")
|
||
if reply == QMessageBox.Yes:
|
||
try:
|
||
with self.get_conn() as conn:
|
||
conn.execute("DELETE FROM garment_materials WHERE style_number = ?", (style_number,))
|
||
conn.execute("DELETE FROM garments WHERE style_number = ?", (style_number,))
|
||
conn.commit()
|
||
self.load_garments()
|
||
QMessageBox.information(self, "成功", "删除完成")
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", "删除失败: " + str(e))
|
||
|
||
|
||
class GarmentEditDialog(QDialog):
|
||
"""服装编辑对话框"""
|
||
|
||
def __init__(self, db_path, style_number=None):
|
||
super().__init__()
|
||
self.db_path = db_path
|
||
self.style_number = style_number
|
||
self.current_image_path = None
|
||
self.setWindowTitle("编辑款号" if style_number else "新增款号")
|
||
self.resize(1300, 850)
|
||
|
||
self.setup_ui()
|
||
if style_number:
|
||
self.load_garment_data()
|
||
|
||
def setup_ui(self):
|
||
"""设置用户界面"""
|
||
layout = QVBoxLayout(self)
|
||
|
||
# 基本信息区域
|
||
basic_layout = QGridLayout()
|
||
basic_layout.addWidget(QLabel("款号:"), 0, 0, Qt.AlignRight)
|
||
self.style_input = QLineEdit()
|
||
if self.style_number:
|
||
self.style_input.setText(self.style_number)
|
||
self.style_input.setEnabled(not self.style_number)
|
||
basic_layout.addWidget(self.style_input, 0, 1)
|
||
|
||
basic_layout.addWidget(QLabel("款式图:"), 1, 0, Qt.AlignRight)
|
||
self.image_label = QLabel("无图片")
|
||
self.image_label.setFixedSize(300, 300)
|
||
self.image_label.setStyleSheet("border: 1px solid gray;")
|
||
self.image_label.setAlignment(Qt.AlignCenter)
|
||
self.image_label.setScaledContents(True)
|
||
basic_layout.addWidget(self.image_label, 1, 1, 5, 1)
|
||
|
||
upload_btn = QPushButton("上传/更换图片")
|
||
upload_btn.clicked.connect(self.upload_image)
|
||
basic_layout.addWidget(upload_btn, 1, 2)
|
||
|
||
layout.addLayout(basic_layout)
|
||
|
||
# 材料用量区域
|
||
layout.addWidget(QLabel("材料用量(单件):"))
|
||
|
||
self.material_table = QTableWidget()
|
||
self.material_table.setColumnCount(6)
|
||
self.material_table.setHorizontalHeaderLabels(["类目", "类型", "型号", "单件用量", "单位", "删除"])
|
||
self.material_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
||
layout.addWidget(self.material_table)
|
||
|
||
# 按钮区域
|
||
btn_layout = QHBoxLayout()
|
||
add_default_btn = QPushButton("快速添加标准类目")
|
||
add_default_btn.clicked.connect(self.add_default_categories)
|
||
btn_layout.addWidget(add_default_btn)
|
||
|
||
add_custom_btn = QPushButton("添加自定义类目")
|
||
add_custom_btn.clicked.connect(lambda: self.add_material_row())
|
||
btn_layout.addWidget(add_custom_btn)
|
||
|
||
layout.addLayout(btn_layout)
|
||
|
||
# 保存/取消按钮
|
||
buttons = QHBoxLayout()
|
||
save_btn = QPushButton("保存")
|
||
save_btn.clicked.connect(self.save_garment)
|
||
buttons.addWidget(save_btn)
|
||
|
||
cancel_btn = QPushButton("取消")
|
||
cancel_btn.clicked.connect(self.reject)
|
||
buttons.addWidget(cancel_btn)
|
||
|
||
layout.addLayout(buttons)
|
||
|
||
def get_conn(self):
|
||
"""获取数据库连接"""
|
||
return get_db_connection(self.db_path)
|
||
|
||
def upload_image(self):
|
||
"""上传图片"""
|
||
file_path, _ = QFileDialog.getOpenFileName(self, "选择图片", "", "Images (*.png *.jpg *.jpeg *.bmp)")
|
||
if file_path:
|
||
try:
|
||
img = Image.open(file_path).convert("RGB")
|
||
img.thumbnail((800, 800))
|
||
os.makedirs("images", exist_ok=True)
|
||
filename = os.path.basename(file_path)
|
||
save_path = os.path.join("images", filename)
|
||
img.save(save_path, "JPEG", quality=85)
|
||
|
||
self.current_image_path = save_path
|
||
pixmap = QPixmap(save_path).scaled(300, 300, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||
self.image_label.setPixmap(pixmap)
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", "上传图片失败: " + str(e))
|
||
|
||
def load_garment_data(self):
|
||
"""加载服装数据"""
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute("SELECT image_path FROM garments WHERE style_number = ?", (self.style_number,))
|
||
row = cursor.fetchone()
|
||
if row and row[0] and os.path.exists(row[0]):
|
||
self.current_image_path = row[0]
|
||
pixmap = QPixmap(row[0]).scaled(300, 300, Qt.KeepAspectRatio, Qt.SmoothTransformation)
|
||
self.image_label.setPixmap(pixmap)
|
||
self.load_materials()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", "加载失败: " + str(e))
|
||
|
||
def load_materials(self):
|
||
"""加载材料列表"""
|
||
try:
|
||
with self.get_conn() as conn:
|
||
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:
|
||
QMessageBox.critical(self, "错误", "加载材料失败: " + str(e))
|
||
|
||
def add_default_categories(self):
|
||
"""添加默认类目"""
|
||
defaults = [("A料", "", "米"), ("B料", "", "米"), ("C料", "", "米"), ("D料", "", "米"),
|
||
("花边", "", "码"), ("胸杯", "", "一对"), ("拉链", "", "个"), ("辅料", "", "个")]
|
||
for cat, fabric_type, unit in defaults:
|
||
self.add_material_row(cat, fabric_type, 0, unit)
|
||
|
||
def add_material_row(self, category="", fabric_type="", usage=0.0, unit="米", model=""):
|
||
"""添加材料行"""
|
||
row = self.material_table.rowCount()
|
||
self.material_table.insertRow(row)
|
||
|
||
# 列0: 类目下拉框
|
||
cat_combo = QComboBox()
|
||
cat_combo.setEditable(False)
|
||
# 最后添加自定义选项
|
||
cat_combo.addItem("—— 自定义类目 ——")
|
||
|
||
# 先添加所有类目选项
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT category
|
||
FROM fabrics
|
||
WHERE category IS NOT NULL AND 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])
|
||
|
||
for cat in sorted(categories):
|
||
cat_combo.addItem(cat)
|
||
except:
|
||
# 如果查询失败,使用默认类目
|
||
cat_combo.addItem("布料")
|
||
cat_combo.addItem("辅料")
|
||
cat_combo.addItem("其他")
|
||
|
||
if category:
|
||
cat_combo.setCurrentText(category)
|
||
else:
|
||
# 如果没有指定类目,默认选择"—— 自定义类目 ——"(索引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)
|
||
|
||
self.material_table.setCellWidget(row, 0, cat_combo)
|
||
|
||
# 列1: 类型下拉框
|
||
type_combo = QComboBox()
|
||
type_combo.setEditable(False)
|
||
# 最后添加选择提示
|
||
type_combo.addItem("—— 选择类型 ——")
|
||
# 先添加所有类型选项
|
||
try:
|
||
with self.get_conn() as conn:
|
||
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].strip():
|
||
type_combo.addItem(type_row[0])
|
||
except:
|
||
pass
|
||
|
||
|
||
if fabric_type:
|
||
type_combo.setCurrentText(fabric_type)
|
||
else:
|
||
# 如果没有指定类型,默认选择"—— 选择类型 ——"(索引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)
|
||
|
||
self.material_table.setCellWidget(row, 1, type_combo)
|
||
|
||
# 列2: 型号下拉框
|
||
model_combo = QComboBox()
|
||
model_combo.setEditable(False)
|
||
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
|
||
|
||
if fabric_type:
|
||
model_combo.setCurrentText(fabric_type)
|
||
else:
|
||
# 如果没有指定类型,默认选择"—— 选择类型 ——"(索引0)
|
||
print("没有指定类型,默认选择'—— 选择类型 ——'(索引0)")
|
||
print(model_combo.count())
|
||
print(model_combo.currentIndex())
|
||
# 打印所有选项
|
||
for i in range(model_combo.count()):
|
||
print(model_combo.itemText(i))
|
||
model_combo.setCurrentIndex(0)
|
||
|
||
self.material_table.setCellWidget(row, 2, model_combo)
|
||
|
||
# 列3: 单件用量
|
||
usage_spin = QDoubleSpinBox()
|
||
usage_spin.setRange(0, 1000)
|
||
usage_spin.setValue(usage)
|
||
usage_spin.setDecimals(3)
|
||
self.material_table.setCellWidget(row, 3, usage_spin)
|
||
|
||
# 列4: 单位
|
||
unit_combo = QComboBox()
|
||
unit_combo.setEditable(True)
|
||
unit_combo.addItems(["米", "码", "公斤", "一对", "个", "条"])
|
||
unit_combo.setCurrentText(unit)
|
||
self.material_table.setCellWidget(row, 4, unit_combo)
|
||
|
||
# 列5: 删除按钮
|
||
del_btn = QPushButton("删除")
|
||
del_btn.clicked.connect(lambda _, r=row: self.material_table.removeRow(r))
|
||
self.material_table.setCellWidget(row, 5, del_btn)
|
||
|
||
# 初始化类型和型号选项
|
||
# self.on_category_changed(cat_combo.currentText(), 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)
|
||
|
||
# # 然后设置型号
|
||
# 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.currentTextChanged.connect(lambda text, r=row: self.on_model_selected(text, r))
|
||
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)
|
||
|
||
# 清空类型下拉框
|
||
type_combo.clear()
|
||
type_combo.addItem("—— 选择类型 ——")
|
||
|
||
# 重新初始化型号下拉框,显示所有型号(阻止信号防止触发on_model_selected)
|
||
model_combo.blockSignals(True)
|
||
model_combo.clear()
|
||
model_combo.addItem("—— 选择型号 ——")
|
||
|
||
try:
|
||
with self.get_conn() as conn:
|
||
# 加载所有类型
|
||
if category_text and category_text != "—— 自定义类目 ——":
|
||
# 如果选择了具体类目,则过滤
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT fabric_type
|
||
FROM fabrics
|
||
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
|
||
""")
|
||
|
||
types = cursor.fetchall()
|
||
for type_row in types:
|
||
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))
|
||
|
||
# 加载该类目下的所有型号到型号下拉框
|
||
if category_text and category_text != "—— 自定义类目 ——":
|
||
# 如果选择了具体类目,则只加载该类目下的型号
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT model, color, unit
|
||
FROM fabrics
|
||
WHERE category = ?
|
||
ORDER BY model
|
||
""", (category_text,))
|
||
else:
|
||
# 如果是自定义类目,加载所有型号
|
||
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
|
||
finally:
|
||
# 恢复信号
|
||
model_combo.blockSignals(False)
|
||
|
||
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 not model_combo:
|
||
return
|
||
|
||
# 如果选择了具体类型,自动选中该类型对应的类目
|
||
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 = cursor.fetchone()
|
||
if row and row[0]:
|
||
category = row[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
|
||
|
||
# 重新初始化型号下拉框,显示该类型下的所有型号
|
||
model_combo.blockSignals(True)
|
||
model_combo.clear()
|
||
model_combo.addItem("—— 选择型号 ——")
|
||
|
||
# 根据类型和类目过滤型号
|
||
try:
|
||
with self.get_conn() as conn:
|
||
# 获取当前选择的类目(可能已经更新)
|
||
category_text = cat_combo.currentText() if cat_combo else ""
|
||
|
||
# 构建查询条件
|
||
if type_text and type_text != "—— 选择类型 ——":
|
||
# 如果选择了具体类型
|
||
if category_text and category_text != "—— 自定义类目 ——":
|
||
# 同时根据类目和类型过滤
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT model, color, unit
|
||
FROM fabrics
|
||
WHERE category = ? AND fabric_type = ?
|
||
ORDER BY model
|
||
""", (category_text, type_text))
|
||
else:
|
||
# 只根据类型过滤
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT model, color, unit
|
||
FROM fabrics
|
||
WHERE fabric_type = ?
|
||
ORDER BY model
|
||
""", (type_text,))
|
||
else:
|
||
# 如果没有选择类型,根据类目过滤(如果有类目)
|
||
if category_text and category_text != "—— 自定义类目 ——":
|
||
cursor = conn.execute("""
|
||
SELECT DISTINCT model, color, unit
|
||
FROM fabrics
|
||
WHERE category = ?
|
||
ORDER BY model
|
||
""", (category_text,))
|
||
else:
|
||
# 显示所有型号
|
||
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.blockSignals(False)
|
||
|
||
def on_model_selected(self, model_text, row):
|
||
"""当型号选择时,自动设置单位并填充类目和类型"""
|
||
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)
|
||
|
||
if not model_text or model_text == "—— 选择型号 ——":
|
||
# 获取当前类目和类型下的所有型号,阻止信号防止死循环
|
||
model_combo.blockSignals(True)
|
||
try:
|
||
model_combo.clear()
|
||
model_combo.addItem("—— 选择型号 ——")
|
||
|
||
try:
|
||
with self.get_conn() as conn:
|
||
if cat_combo.currentText() != "—— 自定义类目 ——" and type_combo.currentText() != "—— 选择类型 ——":
|
||
cursor = conn.execute("SELECT DISTINCT model, color, unit FROM fabrics WHERE category = ? AND fabric_type = ? ORDER BY model", (cat_combo.currentText(), type_combo.currentText()))
|
||
elif cat_combo.currentText() != "—— 自定义类目 ——" and type_combo.currentText() == "—— 选择类型 ——":
|
||
cursor = conn.execute("SELECT DISTINCT model, color, unit FROM fabrics WHERE category = ? ORDER BY model", (cat_combo.currentText(),))
|
||
else:
|
||
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)
|
||
finally:
|
||
# 恢复信号
|
||
model_combo.blockSignals(False)
|
||
return
|
||
|
||
# 获取选中项的数据
|
||
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, fabric_type, unit FROM fabrics WHERE model = ?", (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在finally中恢复了信号)
|
||
# 这可以防止死循环
|
||
model_combo.blockSignals(True)
|
||
|
||
# 重新设置选中的型号(因为on_category_changed会清空并重新加载型号下拉框)
|
||
# 查找并选中对应的型号
|
||
for i in range(model_combo.count()):
|
||
item_data = model_combo.itemData(i)
|
||
if item_data == model:
|
||
model_combo.setCurrentIndex(i)
|
||
break
|
||
|
||
# 设置类型
|
||
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):
|
||
"""保存服装"""
|
||
style_number = self.style_input.text().strip()
|
||
if not style_number:
|
||
QMessageBox.warning(self, "错误", "请输入款号")
|
||
return
|
||
|
||
try:
|
||
with self.get_conn() as conn:
|
||
conn.execute('INSERT OR REPLACE INTO garments (style_number, image_path) VALUES (?, ?)',
|
||
(style_number, self.current_image_path))
|
||
|
||
conn.execute("DELETE FROM garment_materials WHERE style_number = ?", (style_number,))
|
||
|
||
for row in range(self.material_table.rowCount()):
|
||
# 获取各列的值
|
||
category_widget = self.material_table.cellWidget(row, 0) # 类目
|
||
type_widget = self.material_table.cellWidget(row, 1) # 类型
|
||
model_widget = self.material_table.cellWidget(row, 2) # 型号
|
||
usage_widget = self.material_table.cellWidget(row, 3) # 单件用量
|
||
unit_widget = self.material_table.cellWidget(row, 4) # 单位
|
||
|
||
category = category_widget.currentText().strip()
|
||
fabric_type = type_widget.currentText().strip()
|
||
model = model_widget.currentText().strip()
|
||
|
||
# 处理类目和类型
|
||
if category == "—— 自定义类目 ——":
|
||
category = ""
|
||
if fabric_type == "—— 选择类型 ——":
|
||
fabric_type = ""
|
||
|
||
# 如果选择了具体型号,获取型号的实际值
|
||
final_model = ""
|
||
if model and model != "—— 选择型号 ——":
|
||
model_data = model_widget.itemData(model_widget.currentIndex())
|
||
final_model = model_data if model_data else model
|
||
|
||
# 至少需要有类目或型号
|
||
if not category and not final_model:
|
||
continue
|
||
|
||
usage = usage_widget.value()
|
||
unit = unit_widget.currentText().strip() or "米"
|
||
|
||
# 分别存储类目、类型和型号到对应字段
|
||
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, "成功", "保存完成")
|
||
self.accept()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", "保存失败: " + str(e)) |