优化原料库存管理功能
- 库存跟踪表格设置为只读模式,防止误编辑 - 添加"编辑剩余库存"功能,支持直接修改库存数量 - 实现逻辑删除机制,删除操作不再物理删除数据 - 在 fabric_stock_in 和 fabric_consumption 表添加 is_deleted 字段 - 所有删除操作改为标记删除,保留历史数据 - 查询时自动过滤已删除记录 - 原料编辑支持修改型号 - 型号字段改为可编辑 - 保存时检查型号重复并提示 - 型号修改时级联更新所有关联表 - 优化操作列宽度,确保按钮文本完整显示 - 改进警告提示,明确说明操作影响 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
12
database.py
12
database.py
@@ -143,7 +143,17 @@ class DatabaseManager:
|
|||||||
conn.execute("ALTER TABLE fabric_consumption ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP")
|
conn.execute("ALTER TABLE fabric_consumption ADD COLUMN updated_at DATETIME DEFAULT CURRENT_TIMESTAMP")
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 添加逻辑删除字段
|
||||||
|
try:
|
||||||
|
conn.execute("ALTER TABLE fabric_stock_in ADD COLUMN is_deleted INTEGER DEFAULT 0")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
conn.execute("ALTER TABLE fabric_consumption ADD COLUMN is_deleted INTEGER DEFAULT 0")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# 数据迁移:将fabrics表中category字段的"类目-类型"格式拆分成两个字段
|
# 数据迁移:将fabrics表中category字段的"类目-类型"格式拆分成两个字段
|
||||||
try:
|
try:
|
||||||
cursor = conn.execute("SELECT model, category FROM fabrics WHERE category LIKE '%-%' AND (fabric_type IS NULL OR fabric_type = '')")
|
cursor = conn.execute("SELECT model, category FROM fabrics WHERE category LIKE '%-%' AND (fabric_type IS NULL OR fabric_type = '')")
|
||||||
|
|||||||
Binary file not shown.
@@ -44,8 +44,6 @@ class RawMaterialEditDialog(QDialog):
|
|||||||
# 基本信息
|
# 基本信息
|
||||||
layout.addWidget(QLabel("型号:"), 1, 0, Qt.AlignRight)
|
layout.addWidget(QLabel("型号:"), 1, 0, Qt.AlignRight)
|
||||||
self.edit_model = QLineEdit()
|
self.edit_model = QLineEdit()
|
||||||
self.edit_model.setReadOnly(True) # 型号不可修改
|
|
||||||
self.edit_model.setStyleSheet("background-color: #f0f0f0;")
|
|
||||||
layout.addWidget(self.edit_model, 1, 1, 1, 3)
|
layout.addWidget(self.edit_model, 1, 1, 1, 3)
|
||||||
|
|
||||||
layout.addWidget(QLabel("供应商:"), 2, 0, Qt.AlignRight)
|
layout.addWidget(QLabel("供应商:"), 2, 0, Qt.AlignRight)
|
||||||
@@ -164,6 +162,13 @@ class RawMaterialEditDialog(QDialog):
|
|||||||
|
|
||||||
def save_changes(self):
|
def save_changes(self):
|
||||||
"""保存修改"""
|
"""保存修改"""
|
||||||
|
new_model = self.edit_model.text().strip()
|
||||||
|
|
||||||
|
# 检查型号是否为空
|
||||||
|
if not new_model:
|
||||||
|
QMessageBox.warning(self, "错误", "型号不能为空")
|
||||||
|
return
|
||||||
|
|
||||||
major = self.edit_major_category.currentText().strip()
|
major = self.edit_major_category.currentText().strip()
|
||||||
sub = self.edit_sub_category.text().strip()
|
sub = self.edit_sub_category.text().strip()
|
||||||
|
|
||||||
@@ -179,24 +184,64 @@ class RawMaterialEditDialog(QDialog):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with self.get_conn() as conn:
|
with self.get_conn() as conn:
|
||||||
conn.execute('''
|
# 如果型号被修改了,检查新型号是否已存在
|
||||||
UPDATE fabrics
|
if new_model != self.model:
|
||||||
SET category=?, fabric_type=?, supplier=?, color=?, width=?, gsm=?,
|
cursor = conn.execute("SELECT model FROM fabrics WHERE model = ?", (new_model,))
|
||||||
retail_price=?, bulk_price=?, unit=?, timestamp=?
|
if cursor.fetchone():
|
||||||
WHERE model=?
|
QMessageBox.warning(self, "错误", f"型号 '{new_model}' 已存在,请使用其他型号")
|
||||||
''', (
|
return
|
||||||
category, fabric_type, supplier, color,
|
|
||||||
self.edit_width.value() or None,
|
# 型号被修改,需要更新所有相关表
|
||||||
self.edit_gsm.value() or None,
|
# 更新原料表
|
||||||
self.edit_retail.value() or None,
|
conn.execute('''
|
||||||
self.edit_bulk.value() or None,
|
UPDATE fabrics
|
||||||
unit,
|
SET model=?, category=?, fabric_type=?, supplier=?, color=?, width=?, gsm=?,
|
||||||
datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
retail_price=?, bulk_price=?, unit=?, timestamp=?
|
||||||
self.model
|
WHERE model=?
|
||||||
))
|
''', (
|
||||||
|
new_model, category, fabric_type, supplier, color,
|
||||||
|
self.edit_width.value() or None,
|
||||||
|
self.edit_gsm.value() or None,
|
||||||
|
self.edit_retail.value() or None,
|
||||||
|
self.edit_bulk.value() or None,
|
||||||
|
unit,
|
||||||
|
datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
self.model
|
||||||
|
))
|
||||||
|
|
||||||
|
# 更新入库记录表
|
||||||
|
conn.execute("UPDATE fabric_stock_in SET model=? WHERE model=?", (new_model, self.model))
|
||||||
|
|
||||||
|
# 更新消耗记录表
|
||||||
|
conn.execute("UPDATE fabric_consumption SET model=? WHERE model=?", (new_model, self.model))
|
||||||
|
|
||||||
|
# 更新衣服材料用量表
|
||||||
|
conn.execute("UPDATE garment_materials SET model=? WHERE model=?", (new_model, self.model))
|
||||||
|
|
||||||
|
else:
|
||||||
|
# 型号未修改,只更新其他字段
|
||||||
|
conn.execute('''
|
||||||
|
UPDATE fabrics
|
||||||
|
SET category=?, fabric_type=?, supplier=?, color=?, width=?, gsm=?,
|
||||||
|
retail_price=?, bulk_price=?, unit=?, timestamp=?
|
||||||
|
WHERE model=?
|
||||||
|
''', (
|
||||||
|
category, fabric_type, supplier, color,
|
||||||
|
self.edit_width.value() or None,
|
||||||
|
self.edit_gsm.value() or None,
|
||||||
|
self.edit_retail.value() or None,
|
||||||
|
self.edit_bulk.value() or None,
|
||||||
|
unit,
|
||||||
|
datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
||||||
|
self.model
|
||||||
|
))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
QMessageBox.information(self, "成功", f"已更新 '{self.model}'")
|
if new_model != self.model:
|
||||||
|
QMessageBox.information(self, "成功", f"已将 '{self.model}' 更新为 '{new_model}'")
|
||||||
|
else:
|
||||||
|
QMessageBox.information(self, "成功", f"已更新 '{self.model}'")
|
||||||
self.accept()
|
self.accept()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -380,7 +425,13 @@ class RawMaterialLibraryDialog(QDialog):
|
|||||||
self.stock_table = QTableWidget()
|
self.stock_table = QTableWidget()
|
||||||
self.stock_table.setColumnCount(len(stock_headers))
|
self.stock_table.setColumnCount(len(stock_headers))
|
||||||
self.stock_table.setHorizontalHeaderLabels(stock_headers)
|
self.stock_table.setHorizontalHeaderLabels(stock_headers)
|
||||||
self.stock_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
|
self.stock_table.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
|
||||||
|
# 设置操作列固定宽度,其他列自动拉伸
|
||||||
|
for i in range(6):
|
||||||
|
self.stock_table.horizontalHeader().setSectionResizeMode(i, QHeaderView.Stretch)
|
||||||
|
self.stock_table.horizontalHeader().setSectionResizeMode(6, QHeaderView.Fixed)
|
||||||
|
self.stock_table.setColumnWidth(6, 400) # 操作列固定宽度400像素
|
||||||
|
self.stock_table.setEditTriggers(QTableWidget.NoEditTriggers) # 设置为只读模式
|
||||||
stock_layout.addWidget(self.stock_table)
|
stock_layout.addWidget(self.stock_table)
|
||||||
|
|
||||||
return stock_tab
|
return stock_tab
|
||||||
@@ -664,8 +715,8 @@ class RawMaterialLibraryDialog(QDialog):
|
|||||||
with self.get_conn() as conn:
|
with self.get_conn() as conn:
|
||||||
cursor = conn.execute('''
|
cursor = conn.execute('''
|
||||||
SELECT f.model, f.color, f.unit,
|
SELECT f.model, f.color, f.unit,
|
||||||
COALESCE(SUM(si.quantity), 0) AS total_in,
|
COALESCE(SUM(CASE WHEN si.is_deleted = 0 THEN si.quantity ELSE 0 END), 0) AS total_in,
|
||||||
COALESCE(SUM(c.consume_quantity), 0) AS total_out
|
COALESCE(SUM(CASE WHEN c.is_deleted = 0 THEN c.consume_quantity ELSE 0 END), 0) AS total_out
|
||||||
FROM fabrics f
|
FROM fabrics f
|
||||||
LEFT JOIN fabric_stock_in si ON f.model = si.model
|
LEFT JOIN fabric_stock_in si ON f.model = si.model
|
||||||
LEFT JOIN fabric_consumption c ON f.model = c.model
|
LEFT JOIN fabric_consumption c ON f.model = c.model
|
||||||
@@ -694,6 +745,10 @@ class RawMaterialLibraryDialog(QDialog):
|
|||||||
detail_btn.clicked.connect(lambda _, m=model: self.show_stock_detail(m))
|
detail_btn.clicked.connect(lambda _, m=model: self.show_stock_detail(m))
|
||||||
op_layout.addWidget(detail_btn)
|
op_layout.addWidget(detail_btn)
|
||||||
|
|
||||||
|
edit_btn = QPushButton("编辑剩余库存")
|
||||||
|
edit_btn.clicked.connect(lambda _, m=model, u=unit, r=remaining: self.edit_remaining_stock(m, u, r))
|
||||||
|
op_layout.addWidget(edit_btn)
|
||||||
|
|
||||||
clear_btn = QPushButton("一键清零剩余")
|
clear_btn = QPushButton("一键清零剩余")
|
||||||
clear_btn.clicked.connect(lambda _, m=model: self.clear_remaining(m))
|
clear_btn.clicked.connect(lambda _, m=model: self.clear_remaining(m))
|
||||||
op_layout.addWidget(clear_btn)
|
op_layout.addWidget(clear_btn)
|
||||||
@@ -707,14 +762,17 @@ class RawMaterialLibraryDialog(QDialog):
|
|||||||
"""显示库存明细"""
|
"""显示库存明细"""
|
||||||
try:
|
try:
|
||||||
with self.get_conn() as conn:
|
with self.get_conn() as conn:
|
||||||
# 查询入库记录
|
# 查询入库记录(只显示未删除的)
|
||||||
cursor_in = conn.execute("SELECT purchase_date, quantity, unit, note FROM fabric_stock_in WHERE model = ? ORDER BY purchase_date DESC", (model,))
|
cursor_in = conn.execute(
|
||||||
|
"SELECT purchase_date, quantity, unit, note FROM fabric_stock_in WHERE model = ? AND is_deleted = 0 ORDER BY purchase_date DESC",
|
||||||
|
(model,)
|
||||||
|
)
|
||||||
in_rows = cursor_in.fetchall()
|
in_rows = cursor_in.fetchall()
|
||||||
|
|
||||||
# 查询消耗记录
|
# 查询消耗记录(只显示未删除的)
|
||||||
cursor_out = conn.execute('''
|
cursor_out = conn.execute('''
|
||||||
SELECT consume_date, style_number, quantity_made, loss_rate, consume_quantity, unit
|
SELECT consume_date, style_number, quantity_made, loss_rate, consume_quantity, unit
|
||||||
FROM fabric_consumption WHERE model = ? ORDER BY consume_date DESC
|
FROM fabric_consumption WHERE model = ? AND is_deleted = 0 ORDER BY consume_date DESC
|
||||||
''', (model,))
|
''', (model,))
|
||||||
out_rows = cursor_out.fetchall()
|
out_rows = cursor_out.fetchall()
|
||||||
|
|
||||||
@@ -750,78 +808,152 @@ class RawMaterialLibraryDialog(QDialog):
|
|||||||
QMessageBox.critical(self, "错误", str(e))
|
QMessageBox.critical(self, "错误", str(e))
|
||||||
|
|
||||||
def clear_remaining(self, model):
|
def clear_remaining(self, model):
|
||||||
"""清零剩余库存"""
|
"""清零剩余库存(逻辑删除)"""
|
||||||
reply = QMessageBox.question(
|
reply = QMessageBox.warning(
|
||||||
self,
|
self,
|
||||||
"确认清零",
|
"确认清零",
|
||||||
f"确定将 {model} 的剩余量清零?"
|
f"确定将 {model} 的剩余量清零吗?\n\n"
|
||||||
|
"此操作将标记删除该原料的所有历史采购和消耗记录。",
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No
|
||||||
)
|
)
|
||||||
if reply != QMessageBox.Yes:
|
if reply != QMessageBox.Yes:
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self.get_conn() as conn:
|
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(
|
conn.execute(
|
||||||
"""
|
"UPDATE fabric_stock_in SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE model = ? AND is_deleted = 0",
|
||||||
INSERT INTO fabric_consumption
|
(model,)
|
||||||
(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.execute(
|
||||||
|
"UPDATE fabric_consumption SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE model = ? AND is_deleted = 0",
|
||||||
|
(model,)
|
||||||
|
)
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
self,
|
self,
|
||||||
"完成",
|
"完成",
|
||||||
f"{model} 剩余量 {remaining:.3f} {unit} 已清零。"
|
f"{model} 的剩余库存已清零。"
|
||||||
)
|
)
|
||||||
self.load_stock_table()
|
self.load_stock_table()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
QMessageBox.critical(self, "错误", f"清零失败: {str(e)}")
|
QMessageBox.critical(self, "错误", f"清零失败: {str(e)}")
|
||||||
|
|
||||||
|
def edit_remaining_stock(self, model, unit, current_remaining):
|
||||||
|
"""编辑剩余库存"""
|
||||||
|
from PyQt5.QtWidgets import QDialogButtonBox
|
||||||
|
|
||||||
|
# 创建编辑对话框
|
||||||
|
dialog = QDialog(self)
|
||||||
|
dialog.setWindowTitle(f"编辑剩余库存 - {model}")
|
||||||
|
dialog.resize(400, 200)
|
||||||
|
|
||||||
|
layout = QVBoxLayout(dialog)
|
||||||
|
|
||||||
|
# 显示当前剩余量
|
||||||
|
info_label = QLabel(f"当前剩余量: {current_remaining:.3f} {unit}")
|
||||||
|
info_label.setStyleSheet("font-weight: bold; color: #2196F3; font-size: 14px;")
|
||||||
|
layout.addWidget(info_label)
|
||||||
|
|
||||||
|
# 新剩余量输入
|
||||||
|
input_layout = QHBoxLayout()
|
||||||
|
input_layout.addWidget(QLabel("新剩余量:"))
|
||||||
|
new_remaining_input = QDoubleSpinBox()
|
||||||
|
new_remaining_input.setRange(0, 999999)
|
||||||
|
new_remaining_input.setDecimals(3)
|
||||||
|
new_remaining_input.setValue(current_remaining)
|
||||||
|
input_layout.addWidget(new_remaining_input)
|
||||||
|
input_layout.addWidget(QLabel(unit))
|
||||||
|
layout.addLayout(input_layout)
|
||||||
|
|
||||||
|
# 警告提示
|
||||||
|
warning_label = QLabel(
|
||||||
|
"⚠️ 警告:保存后将删除该原料的所有历史采购和消耗记录!\n"
|
||||||
|
"系统将只保留新设置的剩余库存量。"
|
||||||
|
)
|
||||||
|
warning_label.setStyleSheet(
|
||||||
|
"background-color: #fff3cd; color: #856404; "
|
||||||
|
"padding: 10px; border: 1px solid #ffc107; border-radius: 5px;"
|
||||||
|
)
|
||||||
|
warning_label.setWordWrap(True)
|
||||||
|
layout.addWidget(warning_label)
|
||||||
|
|
||||||
|
# 按钮
|
||||||
|
button_box = QDialogButtonBox(
|
||||||
|
QDialogButtonBox.Save | QDialogButtonBox.Cancel
|
||||||
|
)
|
||||||
|
button_box.accepted.connect(dialog.accept)
|
||||||
|
button_box.rejected.connect(dialog.reject)
|
||||||
|
layout.addWidget(button_box)
|
||||||
|
|
||||||
|
# 显示对话框
|
||||||
|
if dialog.exec_() == QDialog.Accepted:
|
||||||
|
new_remaining = new_remaining_input.value()
|
||||||
|
self.save_new_remaining_stock(model, unit, new_remaining)
|
||||||
|
|
||||||
|
def save_new_remaining_stock(self, model, unit, new_remaining):
|
||||||
|
"""保存新的剩余库存量(逻辑删除历史记录)"""
|
||||||
|
# 二次确认
|
||||||
|
reply = QMessageBox.warning(
|
||||||
|
self,
|
||||||
|
"最后确认",
|
||||||
|
f"确定要将 {model} 的剩余库存设置为 {new_remaining:.3f} {unit} 吗?\n\n"
|
||||||
|
"此操作将:\n"
|
||||||
|
"1. 标记删除该原料的所有历史采购记录\n"
|
||||||
|
"2. 标记删除该原料的所有历史消耗记录\n"
|
||||||
|
"3. 创建一条新的入库记录作为当前库存",
|
||||||
|
QMessageBox.Yes | QMessageBox.No,
|
||||||
|
QMessageBox.No
|
||||||
|
)
|
||||||
|
|
||||||
|
if reply != QMessageBox.Yes:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
with self.get_conn() as conn:
|
||||||
|
# 逻辑删除历史采购记录
|
||||||
|
conn.execute(
|
||||||
|
"UPDATE fabric_stock_in SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE model = ? AND is_deleted = 0",
|
||||||
|
(model,)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 逻辑删除历史消耗记录
|
||||||
|
conn.execute(
|
||||||
|
"UPDATE fabric_consumption SET is_deleted = 1, updated_at = CURRENT_TIMESTAMP WHERE model = ? AND is_deleted = 0",
|
||||||
|
(model,)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 如果新剩余量大于0,创建一条新的入库记录
|
||||||
|
if new_remaining > 0:
|
||||||
|
conn.execute(
|
||||||
|
"""
|
||||||
|
INSERT INTO fabric_stock_in
|
||||||
|
(model, quantity, unit, purchase_date, note, is_deleted)
|
||||||
|
VALUES (?, ?, ?, ?, ?, 0)
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
model,
|
||||||
|
new_remaining,
|
||||||
|
unit,
|
||||||
|
datetime.now().strftime('%Y-%m-%d'),
|
||||||
|
"手动编辑库存"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
QMessageBox.information(
|
||||||
|
self,
|
||||||
|
"成功",
|
||||||
|
f"{model} 的剩余库存已更新为 {new_remaining:.3f} {unit}"
|
||||||
|
)
|
||||||
|
self.load_stock_table()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
QMessageBox.critical(self, "错误", f"保存失败: {str(e)}")
|
||||||
Reference in New Issue
Block a user