600 lines
25 KiB
Python
600 lines
25 KiB
Python
"""
|
||
服装布料计算管理器 - 专业版(最终完整修复版)
|
||
- 修复所有 "name not defined" 错误
|
||
- 衣服库和原料库正常打开
|
||
- 所有功能完整可用
|
||
"""
|
||
|
||
import sys
|
||
import os
|
||
from datetime import datetime
|
||
|
||
from PyQt5.QtWidgets import (
|
||
QApplication, QMainWindow, QWidget, QVBoxLayout, QGridLayout, QHBoxLayout,
|
||
QLabel, QLineEdit, QPushButton, QComboBox, QTextEdit, QMessageBox,
|
||
QGroupBox, QDoubleSpinBox, QSpinBox, QDialog, QScrollArea
|
||
)
|
||
from PyQt5.QtCore import Qt
|
||
from PyQt5.QtGui import QFont
|
||
|
||
from database import get_db_connection
|
||
from login_dialog import LoginDialog
|
||
from stock_dialog import StockInDialog
|
||
from raw_material_dialog import RawMaterialLibraryDialog
|
||
from garment_dialogs import GarmentLibraryDialog
|
||
from purchase_order_dialog import PurchaseOrderDialog
|
||
|
||
|
||
class FabricManager(QMainWindow):
|
||
def __init__(self, is_admin=False):
|
||
super().__init__()
|
||
self.is_admin = is_admin
|
||
|
||
exe_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(__file__)
|
||
self.db_path = os.path.join(exe_dir, "fabric_library.db")
|
||
|
||
self.init_db()
|
||
|
||
mode_text = "(管理员模式)" if is_admin else "(普通模式)"
|
||
self.setWindowTitle("服装布料计算管理器 - 专业版 " + mode_text)
|
||
self.resize(1300, 800)
|
||
|
||
self.setStyleSheet("""
|
||
QMainWindow { background-color: #f0fff8; }
|
||
QGroupBox { font-weight: bold; color: #2e8b57; border: 2px solid #90ee90; border-radius: 10px; margin-top: 10px; padding-top: 8px; background-color: #ffffff; }
|
||
QPushButton { background-color: #4caf50; color: white; padding: 10px; border-radius: 8px; font-size: 13px; font-weight: bold; }
|
||
QTextEdit { background-color: #e8f5e9; border: 2px solid #a5d6a7; border-radius: 8px; padding: 10px; font-size: 13px; }
|
||
QLineEdit, QDoubleSpinBox, QSpinBox, QComboBox { padding: 6px; border: 2px solid #a5d6a7; border-radius: 6px; font-size: 13px; }
|
||
QLabel { font-size: 13px; color: #2e8b57; }
|
||
""")
|
||
|
||
# 提前绑定方法,避免 AttributeError
|
||
self.quick_stock_in = self._quick_stock_in
|
||
self.generate_purchase_order = self._generate_purchase_order
|
||
self.record_current_consumption = self._record_current_consumption
|
||
self.open_library = self._open_library
|
||
self.open_garment_library = self._open_garment_library
|
||
self.load_garment_list = self._load_garment_list
|
||
self.load_garment_materials = self._load_garment_materials
|
||
self.show_guide = self._show_guide
|
||
self.convert_units = self._convert_units
|
||
|
||
self.init_ui()
|
||
self.load_garment_list()
|
||
|
||
def _quick_stock_in(self):
|
||
dialog = StockInDialog(self.db_path)
|
||
dialog.exec_()
|
||
|
||
def _generate_purchase_order(self):
|
||
style_number = self.garment_combo.currentText().strip()
|
||
if not style_number:
|
||
QMessageBox.warning(self, "提示", "请先选择或计算一款号!")
|
||
return
|
||
quantity = self.quantity_input.value()
|
||
loss_rate = self.loss_input.value() / 100
|
||
dialog = PurchaseOrderDialog(self.db_path, style_number, quantity, loss_rate)
|
||
dialog.exec_()
|
||
|
||
def _record_current_consumption(self):
|
||
style_number = self.garment_combo.currentText().strip()
|
||
if not style_number:
|
||
QMessageBox.warning(self, "提示", "请先选择一款号并计算用量!")
|
||
return
|
||
quantity = self.quantity_input.value()
|
||
loss_rate = self.loss_input.value() / 100
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute('''
|
||
SELECT 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:
|
||
if usage_per_piece == 0:
|
||
continue
|
||
|
||
# 获取该原料在入库时使用的单位
|
||
stock_cursor = conn.execute('''
|
||
SELECT unit FROM fabric_stock_in
|
||
WHERE model = ?
|
||
ORDER BY purchase_date DESC
|
||
LIMIT 1
|
||
''', (category,))
|
||
stock_unit_row = stock_cursor.fetchone()
|
||
|
||
# 如果有入库记录,使用入库单位;否则使用原来的单位
|
||
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)
|
||
final_unit = stock_unit
|
||
else:
|
||
consume_qty = usage_per_piece * quantity * (1 + loss_rate)
|
||
final_unit = unit
|
||
else:
|
||
# 没有入库记录,使用原单位
|
||
consume_qty = usage_per_piece * quantity * (1 + loss_rate)
|
||
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))
|
||
inserted += 1
|
||
conn.commit()
|
||
if inserted > 0:
|
||
QMessageBox.information(self, "成功", "本次生产消耗已记录到库存!")
|
||
else:
|
||
QMessageBox.information(self, "提示", "本次没有可记录的原料消耗")
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", str(e))
|
||
|
||
def _open_library(self):
|
||
try:
|
||
dialog = RawMaterialLibraryDialog(self.db_path, self.is_admin)
|
||
dialog.exec_()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", f"打开原料库失败: {str(e)}")
|
||
|
||
def _open_garment_library(self):
|
||
try:
|
||
dialog = GarmentLibraryDialog(self.db_path)
|
||
dialog.exec_()
|
||
self.load_garment_list()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "错误", f"打开衣服库失败: {str(e)}")
|
||
|
||
def _load_garment_list(self):
|
||
current = self.garment_combo.currentText()
|
||
self.garment_combo.blockSignals(True)
|
||
self.garment_combo.clear()
|
||
self.garment_combo.addItem("")
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute("SELECT style_number FROM garments ORDER BY style_number")
|
||
for row in cursor.fetchall():
|
||
self.garment_combo.addItem(row[0])
|
||
except:
|
||
pass
|
||
self.garment_combo.blockSignals(False)
|
||
if current:
|
||
self.garment_combo.setCurrentText(current)
|
||
|
||
def _load_garment_materials(self):
|
||
style_number = self.garment_combo.currentText().strip()
|
||
if not style_number:
|
||
self.result_text.clear()
|
||
return
|
||
|
||
qty = self.quantity_input.value()
|
||
loss = self.loss_input.value() / 100
|
||
|
||
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, 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)
|
||
# 显示材料名称:优先显示型号,否则显示类目-类型,最后只显示类目
|
||
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)
|
||
self.result_text.setText(text)
|
||
|
||
def _show_guide(self):
|
||
guide_text = """
|
||
【服装布料计算管理器 - 专业版 详细使用说明】
|
||
|
||
• 启动时弹出登录界面,默认密码均为 123456
|
||
• 管理员可修改密码
|
||
|
||
• 原料库支持大类/子类/供应商多条件筛选
|
||
• 胸杯自动归类到“辅料”,单位固定“一对”
|
||
|
||
• 衣服编辑支持从原料库选择具体型号(可选),自动填充单位
|
||
• 支持材料行上移/下移/删除
|
||
|
||
• 主界面支持:
|
||
- 批量计算用量(含损耗)
|
||
- 生成采购单(复制或保存TXT)
|
||
- “记录本次消耗到库存”:自动记录生产消耗
|
||
|
||
• 原料库“库存跟踪”Tab:
|
||
- 显示每种原料的总采购、总消耗、当前剩余
|
||
- 查看明细(入库和消耗历史)
|
||
- 一键清零剩余(盘点用完时使用)
|
||
|
||
• 在“原料入库管理”或原料库可多次记录采购入库
|
||
|
||
祝使用愉快!
|
||
"""
|
||
dialog = QDialog(self)
|
||
dialog.setWindowTitle("详细使用说明")
|
||
dialog.resize(800, 700)
|
||
layout = QVBoxLayout(dialog)
|
||
text_area = QTextEdit()
|
||
text_area.setReadOnly(True)
|
||
text_area.setFont(QFont("Microsoft YaHei", 12))
|
||
text_area.setText(guide_text)
|
||
scroll = QScrollArea()
|
||
scroll.setWidgetResizable(True)
|
||
scroll.setWidget(text_area)
|
||
layout.addWidget(scroll)
|
||
close_btn = QPushButton("关闭")
|
||
close_btn.clicked.connect(dialog.accept)
|
||
layout.addWidget(close_btn)
|
||
dialog.exec_()
|
||
|
||
def convert_unit_value(self, value, from_unit, to_unit, fabric_model=None):
|
||
"""单位转换函数:将数值从一个单位转换为另一个单位"""
|
||
if from_unit == to_unit:
|
||
return value
|
||
|
||
# 米 <-> 码 转换
|
||
if from_unit == "米" and to_unit == "码":
|
||
return value / 0.9144
|
||
elif from_unit == "码" and to_unit == "米":
|
||
return value * 0.9144
|
||
|
||
# 长度单位转换为重量单位(需要面料的幅宽和克重信息)
|
||
elif (from_unit in ["米", "码"] and to_unit == "公斤") or (from_unit == "公斤" and to_unit in ["米", "码"]):
|
||
if fabric_model:
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute("SELECT width, gsm FROM fabrics WHERE model = ?", (fabric_model,))
|
||
fabric_info = cursor.fetchone()
|
||
if fabric_info and fabric_info[0] and fabric_info[1]:
|
||
width, gsm = fabric_info
|
||
if width > 0 and gsm > 0:
|
||
if from_unit == "米" and to_unit == "公斤":
|
||
# 米转公斤:米数 * 幅宽(m) * 克重(kg/m²)
|
||
return value * (width / 100) * (gsm / 1000)
|
||
elif from_unit == "码" and to_unit == "公斤":
|
||
# 码转公斤:先转米,再转公斤
|
||
meters = value * 0.9144
|
||
return meters * (width / 100) * (gsm / 1000)
|
||
elif from_unit == "公斤" and to_unit == "米":
|
||
# 公斤转米:公斤 / (幅宽(m) * 克重(kg/m²))
|
||
return value / ((width / 100) * (gsm / 1000))
|
||
elif from_unit == "公斤" and to_unit == "码":
|
||
# 公斤转码:先转米,再转码
|
||
meters = value / ((width / 100) * (gsm / 1000))
|
||
return meters / 0.9144
|
||
except Exception:
|
||
pass
|
||
|
||
# 如果无法转换,返回原值
|
||
return value
|
||
|
||
def _convert_units(self):
|
||
sender = self.sender()
|
||
try:
|
||
if sender == self.calc_m:
|
||
m = self.calc_m.value()
|
||
self.calc_yard.blockSignals(True)
|
||
self.calc_yard.setValue(m / 0.9144)
|
||
self.calc_yard.blockSignals(False)
|
||
|
||
weight = (m * self.calc_width.value() / 100 * self.calc_gsm.value()) / 1000
|
||
self.calc_kg.blockSignals(True)
|
||
self.calc_kg.setValue(weight)
|
||
self.calc_kg.blockSignals(False)
|
||
|
||
elif sender == self.calc_yard:
|
||
yard = self.calc_yard.value()
|
||
m = yard * 0.9144
|
||
self.calc_m.blockSignals(True)
|
||
self.calc_m.setValue(m)
|
||
self.calc_m.blockSignals(False)
|
||
|
||
weight = (m * self.calc_width.value() / 100 * self.calc_gsm.value()) / 1000
|
||
self.calc_kg.blockSignals(True)
|
||
self.calc_kg.setValue(weight)
|
||
self.calc_kg.blockSignals(False)
|
||
|
||
elif sender == self.calc_kg:
|
||
kg = self.calc_kg.value()
|
||
if self.calc_width.value() > 0 and self.calc_gsm.value() > 0:
|
||
m = (kg * 1000 * 100) / (self.calc_width.value() * self.calc_gsm.value())
|
||
self.calc_m.blockSignals(True)
|
||
self.calc_m.setValue(m)
|
||
self.calc_m.blockSignals(False)
|
||
|
||
self.calc_yard.blockSignals(True)
|
||
self.calc_yard.setValue(m / 0.9144)
|
||
self.calc_yard.blockSignals(False)
|
||
|
||
elif sender == self.calc_width or sender == self.calc_gsm:
|
||
# 当幅宽或克重改变时,重新计算公斤数(基于当前米数)
|
||
m = self.calc_m.value()
|
||
if m > 0:
|
||
weight = (m * self.calc_width.value() / 100 * self.calc_gsm.value()) / 1000
|
||
self.calc_kg.blockSignals(True)
|
||
self.calc_kg.setValue(weight)
|
||
self.calc_kg.blockSignals(False)
|
||
except Exception:
|
||
pass
|
||
|
||
def get_conn(self):
|
||
return get_db_connection(self.db_path)
|
||
|
||
def init_db(self):
|
||
try:
|
||
with self.get_conn() as conn:
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS fabrics (
|
||
model TEXT PRIMARY KEY,
|
||
category TEXT DEFAULT '未分类',
|
||
fabric_type TEXT,
|
||
supplier TEXT,
|
||
color TEXT,
|
||
width REAL,
|
||
gsm REAL,
|
||
retail_price REAL,
|
||
bulk_price REAL,
|
||
unit TEXT DEFAULT '米',
|
||
timestamp TEXT
|
||
)
|
||
''')
|
||
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS garments (
|
||
style_number TEXT PRIMARY KEY,
|
||
image_path TEXT
|
||
)
|
||
''')
|
||
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS garment_materials (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
style_number TEXT,
|
||
category TEXT,
|
||
fabric_type TEXT,
|
||
model TEXT,
|
||
usage_per_piece REAL,
|
||
unit TEXT DEFAULT '米'
|
||
)
|
||
''')
|
||
|
||
# 添加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 # 列已存在
|
||
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS admin_settings (
|
||
key TEXT PRIMARY KEY,
|
||
value TEXT
|
||
)
|
||
''')
|
||
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS fabric_stock_in (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
model TEXT,
|
||
quantity REAL,
|
||
unit TEXT,
|
||
purchase_date TEXT,
|
||
note TEXT
|
||
)
|
||
''')
|
||
|
||
conn.execute('''
|
||
CREATE TABLE IF NOT EXISTS fabric_consumption (
|
||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
style_number TEXT,
|
||
model TEXT,
|
||
single_usage REAL,
|
||
quantity_made INTEGER,
|
||
loss_rate REAL,
|
||
consume_quantity REAL,
|
||
consume_date TEXT,
|
||
unit TEXT
|
||
)
|
||
''')
|
||
|
||
if not self.get_setting("admin_password"):
|
||
conn.execute("INSERT INTO admin_settings (key, value) VALUES ('admin_password', ?)", ("123456",))
|
||
if not self.get_setting("user_password"):
|
||
conn.execute("INSERT INTO admin_settings (key, value) VALUES ('user_password', ?)", ("123456",))
|
||
|
||
conn.commit()
|
||
except Exception as e:
|
||
QMessageBox.critical(self, "数据库错误", "无法初始化数据库:" + str(e))
|
||
|
||
def get_setting(self, key):
|
||
try:
|
||
with self.get_conn() as conn:
|
||
cursor = conn.execute("SELECT value FROM admin_settings WHERE key = ?", (key,))
|
||
row = cursor.fetchone()
|
||
return row[0] if row else None
|
||
except:
|
||
return None
|
||
|
||
def init_ui(self):
|
||
scroll = QScrollArea()
|
||
scroll.setWidgetResizable(True)
|
||
central_widget = QWidget()
|
||
scroll.setWidget(central_widget)
|
||
self.setCentralWidget(scroll)
|
||
|
||
main_layout = QVBoxLayout(central_widget)
|
||
|
||
title = QLabel("服装布料计算管理器 - 专业版")
|
||
title.setFont(QFont("Microsoft YaHei", 18, QFont.Bold))
|
||
title.setAlignment(Qt.AlignCenter)
|
||
title.setStyleSheet("color: #228b22; padding: 15px;")
|
||
main_layout.addWidget(title)
|
||
|
||
top_buttons = QHBoxLayout()
|
||
guide_btn = QPushButton("📖 查看使用说明")
|
||
guide_btn.clicked.connect(self.show_guide)
|
||
top_buttons.addWidget(guide_btn)
|
||
|
||
garment_btn = QPushButton("👔 衣服库管理")
|
||
garment_btn.clicked.connect(self.open_garment_library)
|
||
top_buttons.addWidget(garment_btn)
|
||
|
||
library_btn = QPushButton("🗄️ 原料库管理")
|
||
library_btn.clicked.connect(self.open_library)
|
||
top_buttons.addWidget(library_btn)
|
||
|
||
stock_in_btn = QPushButton("📦 快速原料入库")
|
||
stock_in_btn.clicked.connect(self.quick_stock_in)
|
||
top_buttons.addWidget(stock_in_btn)
|
||
|
||
top_buttons.addStretch()
|
||
main_layout.addLayout(top_buttons)
|
||
|
||
content_layout = QHBoxLayout()
|
||
|
||
left_widget = QWidget()
|
||
left_layout = QVBoxLayout(left_widget)
|
||
|
||
calc_group = QGroupBox("批量计算(按衣服款号)")
|
||
calc_layout = QGridLayout()
|
||
calc_layout.setVerticalSpacing(12)
|
||
|
||
calc_layout.addWidget(QLabel("选择衣服款号:"), 0, 0, Qt.AlignRight)
|
||
self.garment_combo = QComboBox()
|
||
self.garment_combo.setEditable(True)
|
||
self.garment_combo.currentIndexChanged.connect(self.load_garment_materials)
|
||
calc_layout.addWidget(self.garment_combo, 0, 1, 1, 2)
|
||
|
||
calc_layout.addWidget(QLabel("生产件数:"), 1, 0, Qt.AlignRight)
|
||
self.quantity_input = QSpinBox()
|
||
self.quantity_input.setRange(1, 1000000)
|
||
self.quantity_input.setValue(1000)
|
||
calc_layout.addWidget(self.quantity_input, 1, 1)
|
||
|
||
calc_layout.addWidget(QLabel("损耗率 (%):"), 2, 0, Qt.AlignRight)
|
||
self.loss_input = QDoubleSpinBox()
|
||
self.loss_input.setRange(0, 50)
|
||
self.loss_input.setValue(5)
|
||
calc_layout.addWidget(self.loss_input, 2, 1)
|
||
|
||
calc_btn = QPushButton("计算本次总用量")
|
||
calc_btn.clicked.connect(self.load_garment_materials)
|
||
calc_layout.addWidget(calc_btn, 3, 0, 1, 3)
|
||
|
||
calc_group.setLayout(calc_layout)
|
||
left_layout.addWidget(calc_group)
|
||
|
||
result_group = QGroupBox("本次生产用量明细")
|
||
result_layout = QVBoxLayout()
|
||
|
||
self.result_text = QTextEdit()
|
||
self.result_text.setReadOnly(True)
|
||
self.result_text.setMinimumHeight(400)
|
||
result_layout.addWidget(self.result_text)
|
||
|
||
btn_layout = QHBoxLayout()
|
||
po_btn = QPushButton("生成采购单")
|
||
po_btn.clicked.connect(self.generate_purchase_order)
|
||
po_btn.setStyleSheet("background-color: #ff9800; font-weight: bold; padding: 12px;")
|
||
btn_layout.addWidget(po_btn)
|
||
|
||
record_btn = QPushButton("记录本次消耗到库存")
|
||
record_btn.clicked.connect(self.record_current_consumption)
|
||
record_btn.setStyleSheet("background-color: #e91e63; color: white; font-weight: bold; padding: 12px;")
|
||
btn_layout.addWidget(record_btn)
|
||
|
||
result_layout.addLayout(btn_layout)
|
||
|
||
result_group.setLayout(result_layout)
|
||
left_layout.addWidget(result_group)
|
||
|
||
content_layout.addWidget(left_widget, stretch=3)
|
||
|
||
right_group = QGroupBox("单位换算计算器")
|
||
right_layout = QGridLayout()
|
||
right_layout.setVerticalSpacing(10)
|
||
|
||
right_layout.addWidget(QLabel("米数:"), 0, 0, Qt.AlignRight)
|
||
self.calc_m = QDoubleSpinBox()
|
||
self.calc_m.setRange(0, 100000)
|
||
self.calc_m.setDecimals(3)
|
||
self.calc_m.valueChanged.connect(self.convert_units)
|
||
right_layout.addWidget(self.calc_m, 0, 1)
|
||
|
||
right_layout.addWidget(QLabel("码数:"), 1, 0, Qt.AlignRight)
|
||
self.calc_yard = QDoubleSpinBox()
|
||
self.calc_yard.setRange(0, 100000)
|
||
self.calc_yard.setDecimals(3)
|
||
self.calc_yard.valueChanged.connect(self.convert_units)
|
||
right_layout.addWidget(self.calc_yard, 1, 1)
|
||
|
||
right_layout.addWidget(QLabel("公斤:"), 2, 0, Qt.AlignRight)
|
||
self.calc_kg = QDoubleSpinBox()
|
||
self.calc_kg.setRange(0, 100000)
|
||
self.calc_kg.setDecimals(6)
|
||
self.calc_kg.valueChanged.connect(self.convert_units)
|
||
right_layout.addWidget(self.calc_kg, 2, 1)
|
||
|
||
right_layout.addWidget(QLabel("幅宽 (cm):"), 3, 0, Qt.AlignRight)
|
||
self.calc_width = QDoubleSpinBox()
|
||
self.calc_width.setRange(50, 300)
|
||
self.calc_width.setValue(150)
|
||
self.calc_width.valueChanged.connect(self.convert_units)
|
||
right_layout.addWidget(self.calc_width, 3, 1)
|
||
|
||
right_layout.addWidget(QLabel("克重 (g/m²):"), 4, 0, Qt.AlignRight)
|
||
self.calc_gsm = QDoubleSpinBox()
|
||
self.calc_gsm.setRange(50, 1000)
|
||
self.calc_gsm.setValue(200)
|
||
self.calc_gsm.valueChanged.connect(self.convert_units)
|
||
right_layout.addWidget(self.calc_gsm, 4, 1)
|
||
|
||
right_group.setLayout(right_layout)
|
||
content_layout.addWidget(right_group, stretch=1)
|
||
|
||
main_layout.addLayout(content_layout)
|
||
main_layout.addStretch()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
app = QApplication(sys.argv)
|
||
exe_dir = os.path.dirname(sys.executable) if getattr(sys, 'frozen', False) else os.path.dirname(__file__)
|
||
db_path = os.path.join(exe_dir, "fabric_library.db")
|
||
login = LoginDialog(db_path)
|
||
if login.exec_() == QDialog.Accepted:
|
||
window = FabricManager(login.is_admin)
|
||
window.show()
|
||
sys.exit(app.exec_()) |