| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723 |
- """
- 采购计划Tab页面
- """
- from PyQt5.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton,
- QTableWidget, QTableWidgetItem, QHeaderView, QMessageBox, QDialog,
- QFormLayout, QComboBox, QDateEdit, QRadioButton, QButtonGroup,
- QDoubleSpinBox, QFileDialog, QTextEdit
- )
- from PyQt5.QtCore import Qt, QDate, QDateTime, pyqtSignal
- from PyQt5.QtGui import QFont, QKeySequence
- from database import Database
- import pandas as pd
- from datetime import datetime
- class PurchasePlanTab(QWidget):
- """采购计划Tab"""
-
- def __init__(self, db: Database, main_window=None):
- super().__init__()
- self.db = db
- self.main_window = main_window # 保存主窗口引用,用于跳转到地磅单
- self.init_ui()
- self.refresh_list()
-
- def init_ui(self):
- """初始化界面"""
- layout = QVBoxLayout()
- layout.setSpacing(10)
- layout.setContentsMargins(15, 15, 15, 15)
-
- # 标题
- title = QLabel("采购计划管理")
- title_font = QFont("微软雅黑", 18, QFont.Bold)
- title.setFont(title_font)
- layout.addWidget(title)
-
- # 按钮区域
- button_layout = QHBoxLayout()
- button_layout.setSpacing(10)
-
- self.add_btn = QPushButton("新增")
- self.add_btn.setMinimumHeight(45)
- self.add_btn.setMinimumWidth(120)
- self.add_btn.setFont(QFont("微软雅黑", 16))
- self.add_btn.setStyleSheet("background-color: #2196F3; color: white; border-radius: 5px;")
- self.add_btn.clicked.connect(self.add_plan)
- self.add_btn.setShortcut(QKeySequence("Ctrl+N"))
-
- self.edit_btn = QPushButton("修改")
- self.edit_btn.setMinimumHeight(45)
- self.edit_btn.setMinimumWidth(120)
- self.edit_btn.setFont(QFont("微软雅黑", 16))
- self.edit_btn.clicked.connect(self.edit_plan)
-
- self.delete_btn = QPushButton("删除")
- self.delete_btn.setMinimumHeight(45)
- self.delete_btn.setMinimumWidth(120)
- self.delete_btn.setFont(QFont("微软雅黑", 16))
- self.delete_btn.setStyleSheet("background-color: #f44336; color: white; border-radius: 5px;")
- self.delete_btn.clicked.connect(self.delete_plan)
- self.delete_btn.setShortcut(QKeySequence("Delete"))
-
- self.import_btn = QPushButton("Excel导入")
- self.import_btn.setMinimumHeight(45)
- self.import_btn.setMinimumWidth(120)
- self.import_btn.setFont(QFont("微软雅黑", 16))
- self.import_btn.setStyleSheet("background-color: #4CAF50; color: white; border-radius: 5px;")
- self.import_btn.clicked.connect(self.import_excel)
-
- self.refresh_btn = QPushButton("刷新")
- self.refresh_btn.setMinimumHeight(45)
- self.refresh_btn.setMinimumWidth(120)
- self.refresh_btn.setFont(QFont("微软雅黑", 16))
- self.refresh_btn.setStyleSheet("""
- QPushButton {
- background-color: #607D8B;
- color: white;
- border-radius: 5px;
- border: none;
- }
- QPushButton:hover {
- background-color: #455A64;
- }
- QPushButton:pressed {
- background-color: #37474F;
- }
- QPushButton:disabled {
- background-color: #BDBDBD;
- color: #757575;
- }
- """)
- self.refresh_btn.setEnabled(True) # 确保按钮是启用状态
- self.refresh_btn.clicked.connect(self.refresh_list)
- self.refresh_btn.setShortcut(QKeySequence("F5"))
-
- button_layout.addWidget(self.add_btn)
- button_layout.addWidget(self.edit_btn)
- button_layout.addWidget(self.delete_btn)
- button_layout.addWidget(self.import_btn)
- button_layout.addWidget(self.refresh_btn)
- button_layout.addStretch()
-
- layout.addLayout(button_layout)
-
- # 表格
- self.table = QTableWidget()
- self.table.setColumnCount(10)
- self.table.setHorizontalHeaderLabels(["序号", "日期", "客户名称", "业务类型", "产品", "规格", "计划量(t)", "车牌号", "备注", "操作"])
- self.table.horizontalHeader().setFont(QFont("微软雅黑", 15, QFont.Bold))
- self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
- self.table.setFont(QFont("微软雅黑", 15))
- self.table.setAlternatingRowColors(True)
- self.table.setSelectionBehavior(QTableWidget.SelectRows)
- self.table.setSelectionMode(QTableWidget.SingleSelection)
-
- layout.addWidget(self.table)
- self.setLayout(layout)
-
- def refresh_list(self):
- """刷新列表"""
- plans = self.db.get_all_purchase_plans()
- self.table.setRowCount(len(plans))
-
- for i, plan in enumerate(plans):
- # 序号
- self.table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
-
- # 日期
- self.table.setItem(i, 1, QTableWidgetItem(plan['plan_date']))
-
- # 客户名称
- self.table.setItem(i, 2, QTableWidgetItem(plan.get('customer_name', '')))
-
- # 业务类型
- self.table.setItem(i, 3, QTableWidgetItem(plan['business_type']))
-
- # 产品
- self.table.setItem(i, 4, QTableWidgetItem(plan['product']))
-
- # 规格(保持字符串格式,不进行数值转换)
- spec_value = plan.get('specification', '')
- self.table.setItem(i, 5, QTableWidgetItem(str(spec_value)))
-
- # 计划量(t)
- self.table.setItem(i, 6, QTableWidgetItem(f"{plan['planned_quantity']:.3f}"))
-
- # 车牌号
- self.table.setItem(i, 7, QTableWidgetItem(plan['vehicle_no']))
-
- # 备注
- remarks = plan.get('remarks', '')
- # 如果备注太长,只显示前50个字符
- remarks_display = remarks[:50] + '...' if len(remarks) > 50 else remarks
- self.table.setItem(i, 8, QTableWidgetItem(remarks_display))
-
- # 操作按钮
- btn_widget = QWidget()
- btn_layout = QHBoxLayout()
- btn_layout.setContentsMargins(5, 2, 5, 2)
-
- jump_btn = QPushButton("跳转到地磅单")
- jump_btn.setFont(QFont("微软雅黑", 14))
- jump_btn.setStyleSheet("background-color: #FF9800; color: white;")
- jump_btn.clicked.connect(lambda checked, pid=plan['id']: self.jump_to_weighing(pid))
-
- btn_layout.addWidget(jump_btn)
- btn_layout.addStretch()
- btn_widget.setLayout(btn_layout)
-
- self.table.setCellWidget(i, 9, btn_widget)
-
- self.table.resizeRowsToContents()
-
- def get_selected_plan_id(self) -> int:
- """获取选中的采购计划ID"""
- current_row = self.table.currentRow()
- if current_row < 0:
- return -1
-
- plans = self.db.get_all_purchase_plans()
- if current_row >= len(plans):
- return -1
-
- return plans[current_row]['id']
-
- def add_plan(self):
- """新增采购计划"""
- dialog = PurchasePlanDialog(self.db, parent=self)
- if dialog.exec_() == QDialog.Accepted:
- self.refresh_list()
-
- def edit_plan(self):
- """修改采购计划"""
- plan_id = self.get_selected_plan_id()
- if plan_id < 0:
- QMessageBox.warning(self, "提示", "请先选择要修改的采购计划")
- return
-
- plan = self.db.get_purchase_plan_by_id(plan_id)
- if not plan:
- QMessageBox.warning(self, "错误", "未找到该采购计划")
- return
-
- dialog = PurchasePlanDialog(self.db, plan=plan, parent=self)
- if dialog.exec_() == QDialog.Accepted:
- self.refresh_list()
-
- def delete_plan(self):
- """删除采购计划"""
- plan_id = self.get_selected_plan_id()
- if plan_id < 0:
- QMessageBox.warning(self, "提示", "请先选择要删除的采购计划")
- return
-
- # 确认删除
- reply = QMessageBox.question(
- self, "确认", "确定要删除该采购计划吗?",
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No
- )
-
- if reply == QMessageBox.Yes:
- if self.db.delete_purchase_plan(plan_id):
- QMessageBox.information(self, "成功", "删除成功!")
- self.refresh_list()
- else:
- QMessageBox.warning(self, "错误", "删除失败")
-
- def import_excel(self):
- """导入Excel文件"""
- file_path, _ = QFileDialog.getOpenFileName(
- self, "选择Excel文件", "", "Excel Files (*.xlsx *.xls)"
- )
-
- if not file_path:
- return
-
- try:
- # 读取Excel文件(默认读取第一个sheet)
- # 先读取列名,确定规格列的位置
- df_temp = pd.read_excel(file_path, sheet_name=0, nrows=0)
- original_columns = df_temp.columns.tolist()
-
- # 构建converters字典,将规格列转换为字符串,保留原始格式
- converters = {}
- for col in original_columns:
- col_clean = col.strip().replace('\n', '').replace('\r', '')
- if col_clean == '规格':
- # 定义转换函数,将规格列转换为字符串
- def spec_converter(x):
- if pd.isna(x):
- return ''
- # 如果是数值类型(可能是百分比被转换成了小数),尝试恢复
- if isinstance(x, (int, float)):
- # 检查是否可能是百分比(0-1之间的小数)
- if 0 <= x <= 1:
- # 转换为百分比字符串
- return f"{x * 100:.0f}%"
- else:
- return str(x)
- return str(x)
- converters[col] = spec_converter
-
- # 读取Excel,使用converters确保规格列为字符串类型
- df = pd.read_excel(file_path, sheet_name=0, converters=converters)
-
- # 去除列名的前后空格和换行符
- df.columns = df.columns.str.strip().str.replace('\n', '').str.replace('\r', '')
-
- # 如果存在规格列,确保NaN值被转换为空字符串
- if '规格' in df.columns:
- df['规格'] = df['规格'].fillna('').astype(str)
-
- # 检查必需的列
- required_columns = ['日期', '业务类型', '产品', '计划量(t)', '车牌号']
- missing_columns = [col for col in required_columns if col not in df.columns]
-
- if missing_columns:
- # 显示实际读取到的列名,方便调试
- actual_columns = ', '.join(df.columns.tolist())
- QMessageBox.warning(
- self, "错误",
- f"Excel文件缺少必需的列:{', '.join(missing_columns)}\n\n"
- f"必需的列:{', '.join(required_columns)}\n"
- f"规格列为可选\n\n"
- f"实际读取到的列名:{actual_columns}"
- )
- return
-
- # 导入数据
- success_count = 0
- error_count = 0
- errors = []
-
- for index, row in df.iterrows():
- try:
- # 处理日期
- plan_date = row['日期']
- if pd.isna(plan_date):
- errors.append(f"第{index + 2}行:日期为空")
- error_count += 1
- continue
-
- # 转换为字符串格式
- if isinstance(plan_date, pd.Timestamp):
- plan_date = plan_date.strftime('%Y-%m-%d')
- elif isinstance(plan_date, datetime):
- plan_date = plan_date.strftime('%Y-%m-%d')
- else:
- plan_date = str(plan_date)
-
- # 处理业务类型
- business_type = str(row['业务类型']).strip()
- if business_type not in ['出库', '入库']:
- errors.append(f"第{index + 2}行:业务类型必须是'出库'或'入库'")
- error_count += 1
- continue
-
- # 处理产品
- product = str(row['产品']).strip()
- if not product:
- errors.append(f"第{index + 2}行:产品为空")
- error_count += 1
- continue
-
- # 处理计划量
- planned_quantity = float(row['计划量(t)'])
- if planned_quantity <= 0:
- errors.append(f"第{index + 2}行:计划量必须大于0")
- error_count += 1
- continue
-
- # 处理车牌号
- vehicle_no = str(row['车牌号']).strip()
- if not vehicle_no:
- errors.append(f"第{index + 2}行:车牌号为空")
- error_count += 1
- continue
-
- # 处理规格(可选)
- specification = ''
- if '规格' in df.columns and not pd.isna(row.get('规格')):
- specification = str(row['规格']).strip()
-
- # 处理客户名称(可选)
- customer_name = ''
- if '客户名称' in df.columns and not pd.isna(row.get('客户名称')):
- customer_name = str(row['客户名称']).strip()
- elif '客户' in df.columns and not pd.isna(row.get('客户')):
- customer_name = str(row['客户']).strip()
-
- # 处理备注(可选)
- remarks = ''
- if '备注' in df.columns and not pd.isna(row.get('备注')):
- remarks = str(row['备注']).strip()
-
- # 插入数据
- data = {
- 'plan_date': plan_date,
- 'business_type': business_type,
- 'product': product,
- 'specification': specification,
- 'planned_quantity': planned_quantity,
- 'vehicle_no': vehicle_no,
- 'customer_name': customer_name,
- 'remarks': remarks
- }
-
- self.db.insert_purchase_plan(data)
- success_count += 1
-
- except Exception as e:
- errors.append(f"第{index + 2}行:{str(e)}")
- error_count += 1
-
- # 显示导入结果
- message = f"导入完成!\n成功:{success_count}条\n失败:{error_count}条"
- if errors:
- message += f"\n\n错误详情:\n" + "\n".join(errors[:10]) # 最多显示10个错误
- if len(errors) > 10:
- message += f"\n...还有{len(errors) - 10}个错误"
-
- if error_count > 0:
- QMessageBox.warning(self, "导入结果", message)
- else:
- QMessageBox.information(self, "导入成功", message)
-
- self.refresh_list()
-
- except Exception as e:
- QMessageBox.critical(self, "错误", f"导入失败:{str(e)}")
-
- def jump_to_weighing(self, plan_id: int):
- """跳转到地磅单并填充信息"""
- plan = self.db.get_purchase_plan_by_id(plan_id)
- if not plan:
- QMessageBox.warning(self, "错误", "未找到该采购计划")
- return
-
- if not self.main_window:
- QMessageBox.warning(self, "错误", "无法访问主窗口")
- return
-
- # 切换到地磅单tab(索引1,因为采购计划是0,地磅单是1)
- self.main_window.tab_widget.setCurrentIndex(1)
-
- # 获取地磅单tab
- weighing_tab = self.main_window.weighing_tab
-
- # 填充信息
- # 车牌号
- weighing_tab.vehicle_no_input.setText(plan['vehicle_no'])
-
- # 业务类型
- business_type = plan['business_type']
- if business_type == '出库':
- weighing_tab.business_sale_radio.setChecked(True)
- elif business_type == '入库':
- weighing_tab.business_purchase_radio.setChecked(True)
-
- # 获取客户名称
- customer_name = plan.get('customer_name', '').strip() if plan.get('customer_name') else ''
-
- # 固定公司名称
- fixed_company_name = "安庆市山峡化工有限公司"
-
- # 第一步:自动维护数据到对应模块(避免手动添加)
- # 1. 自动添加产品到货物模块(如果不存在)
- product_name = plan['product']
- if product_name:
- if not self.db.cargo_exists(product_name):
- try:
- self.db.insert_cargo(product_name)
- # 产品已自动维护到货物模块,无需手动添加
- except Exception as e:
- QMessageBox.warning(self, "警告", f"自动添加货物'{product_name}'失败:{str(e)}")
-
- # 2. 确保"安庆市山峡化工有限公司"在公司列表中(如果不存在则自动添加)
- if not self.db.company_exists(fixed_company_name):
- try:
- self.db.insert_company(fixed_company_name)
- except Exception as e:
- QMessageBox.warning(self, "警告", f"自动添加公司'{fixed_company_name}'失败:{str(e)}")
-
- # 3. 自动添加客户名称到公司模块(如果不存在)
- # 注意:客户名称会自动维护到公司模块,无需手动添加
- if customer_name:
- if not self.db.company_exists(customer_name):
- try:
- self.db.insert_company(customer_name)
- # 客户名称已自动维护到公司模块,无需手动添加
- except Exception as e:
- QMessageBox.warning(self, "警告", f"自动添加客户'{customer_name}'到公司模块失败:{str(e)}")
-
- # 第二步:刷新下拉列表(确保新添加的数据显示)
- weighing_tab.refresh_dropdowns()
-
- # 第三步:填充表单字段
- # 货物名称(产品)
- if product_name:
- index = weighing_tab.cargo_combo.findText(product_name)
- if index >= 0:
- weighing_tab.cargo_combo.setCurrentIndex(index)
-
- # 根据业务类型填充供货单位和收货单位
- if business_type == '入库':
- # 入库:客户名称 -> 供货单位,收货单位固定为"安庆市山峡化工有限公司"
- if customer_name:
- # 设置供货单位为客户名称
- index = weighing_tab.supplier_combo.findText(customer_name)
- if index >= 0:
- weighing_tab.supplier_combo.setCurrentIndex(index)
-
- # 设置收货单位为"安庆市山峡化工有限公司"
- index = weighing_tab.consignee_combo.findText(fixed_company_name)
- if index >= 0:
- weighing_tab.consignee_combo.setCurrentIndex(index)
-
- elif business_type == '出库':
- # 出库:客户名称 -> 收货单位,供货单位固定为"安庆市山峡化工有限公司"
- # 设置供货单位为"安庆市山峡化工有限公司"
- index = weighing_tab.supplier_combo.findText(fixed_company_name)
- if index >= 0:
- weighing_tab.supplier_combo.setCurrentIndex(index)
-
- if customer_name:
- # 设置收货单位为客户名称
- index = weighing_tab.consignee_combo.findText(customer_name)
- if index >= 0:
- weighing_tab.consignee_combo.setCurrentIndex(index)
-
- # 计划量(转换为kg,因为计划量是t)
- planned_quantity_kg = plan['planned_quantity'] * 1000
- weighing_tab.planned_quantity_input.setValue(planned_quantity_kg)
-
- # 先清空备注,然后设置采购计划的备注
- remarks_parts = []
-
- # 规格可以放在备注中
- if plan.get('specification'):
- remarks_parts.append(f"规格:{plan['specification']}")
-
- # 采购计划的备注
- if plan.get('remarks'):
- remarks_parts.append(plan['remarks'])
-
- # 先清空备注,然后设置新的备注内容
- if remarks_parts:
- new_remarks = "\n".join(remarks_parts)
- weighing_tab.remarks_input.setPlainText(new_remarks)
- else:
- weighing_tab.remarks_input.setPlainText("")
-
- # 清空毛重时间和皮重时间
- weighing_tab.gross_weight_time.setDateTime(QDateTime())
- if weighing_tab.gross_weight_time.lineEdit():
- weighing_tab.gross_weight_time.lineEdit().setText("")
-
- weighing_tab.tare_weight_time.setDateTime(QDateTime())
- if weighing_tab.tare_weight_time.lineEdit():
- weighing_tab.tare_weight_time.lineEdit().setText("")
- class PurchasePlanDialog(QDialog):
- """采购计划编辑对话框"""
-
- def __init__(self, db: Database, plan=None, parent=None):
- super().__init__(parent)
- self.db = db
- self.plan = plan
- self.init_ui()
-
- def init_ui(self):
- """初始化对话框界面"""
- if self.plan:
- self.setWindowTitle("修改采购计划")
- else:
- self.setWindowTitle("新增采购计划")
-
- self.setMinimumWidth(500)
-
- layout = QVBoxLayout()
- layout.setSpacing(15)
- layout.setContentsMargins(20, 20, 20, 20)
-
- # 表单
- form_layout = QFormLayout()
- form_layout.setSpacing(15)
-
- # 日期
- date_label = QLabel("日期 *:")
- date_label.setFont(QFont("微软雅黑", 16))
- self.date_input = QDateEdit()
- self.date_input.setMinimumHeight(45)
- self.date_input.setFont(QFont("微软雅黑", 16))
- self.date_input.setCalendarPopup(True)
- self.date_input.setDate(QDate.currentDate())
- self.date_input.setDisplayFormat("yyyy-MM-dd")
- form_layout.addRow(date_label, self.date_input)
-
- # 业务类型
- business_label = QLabel("业务类型 *:")
- business_label.setFont(QFont("微软雅黑", 16))
- self.business_type_group = QButtonGroup()
- self.business_sale_radio = QRadioButton("出库")
- self.business_purchase_radio = QRadioButton("入库")
- self.business_sale_radio.setFont(QFont("微软雅黑", 16))
- self.business_purchase_radio.setFont(QFont("微软雅黑", 16))
- self.business_type_group.addButton(self.business_sale_radio, 0)
- self.business_type_group.addButton(self.business_purchase_radio, 1)
- business_layout = QHBoxLayout()
- business_layout.addWidget(self.business_sale_radio)
- business_layout.addWidget(self.business_purchase_radio)
- business_layout.addStretch()
- business_widget = QWidget()
- business_widget.setLayout(business_layout)
- form_layout.addRow(business_label, business_widget)
-
- # 产品
- product_label = QLabel("产品 *:")
- product_label.setFont(QFont("微软雅黑", 16))
- self.product_input = QLineEdit()
- self.product_input.setMinimumHeight(45)
- self.product_input.setFont(QFont("微软雅黑", 16))
- form_layout.addRow(product_label, self.product_input)
-
- # 规格
- spec_label = QLabel("规格:")
- spec_label.setFont(QFont("微软雅黑", 16))
- self.spec_input = QLineEdit()
- self.spec_input.setMinimumHeight(45)
- self.spec_input.setFont(QFont("微软雅黑", 16))
- form_layout.addRow(spec_label, self.spec_input)
-
- # 计划量(t)
- quantity_label = QLabel("计划量(t) *:")
- quantity_label.setFont(QFont("微软雅黑", 16))
- self.quantity_input = QDoubleSpinBox()
- self.quantity_input.setMinimumHeight(45)
- self.quantity_input.setFont(QFont("微软雅黑", 16))
- self.quantity_input.setDecimals(3)
- self.quantity_input.setMinimum(0.001)
- self.quantity_input.setMaximum(999999)
- form_layout.addRow(quantity_label, self.quantity_input)
-
- # 车牌号
- vehicle_label = QLabel("车牌号 *:")
- vehicle_label.setFont(QFont("微软雅黑", 16))
- self.vehicle_input = QLineEdit()
- self.vehicle_input.setMinimumHeight(45)
- self.vehicle_input.setFont(QFont("微软雅黑", 16))
- form_layout.addRow(vehicle_label, self.vehicle_input)
-
- # 客户名称
- customer_label = QLabel("客户名称:")
- customer_label.setFont(QFont("微软雅黑", 16))
- self.customer_input = QLineEdit()
- self.customer_input.setMinimumHeight(45)
- self.customer_input.setFont(QFont("微软雅黑", 16))
- form_layout.addRow(customer_label, self.customer_input)
-
- # 备注
- remarks_label = QLabel("备注:")
- remarks_label.setFont(QFont("微软雅黑", 16))
- self.remarks_input = QTextEdit()
- self.remarks_input.setMinimumHeight(80)
- self.remarks_input.setFont(QFont("微软雅黑", 16))
- form_layout.addRow(remarks_label, self.remarks_input)
-
- # 如果是在修改模式,填充数据
- if self.plan:
- self.date_input.setDate(QDate.fromString(self.plan['plan_date'], "yyyy-MM-dd"))
- if self.plan['business_type'] == '出库':
- self.business_sale_radio.setChecked(True)
- else:
- self.business_purchase_radio.setChecked(True)
- self.product_input.setText(self.plan['product'])
- self.spec_input.setText(self.plan.get('specification', ''))
- self.quantity_input.setValue(self.plan['planned_quantity'])
- self.vehicle_input.setText(self.plan['vehicle_no'])
- self.customer_input.setText(self.plan.get('customer_name', ''))
- self.remarks_input.setPlainText(self.plan.get('remarks', ''))
-
- layout.addLayout(form_layout)
-
- # 按钮
- button_layout = QHBoxLayout()
- button_layout.addStretch()
-
- ok_btn = QPushButton("确定")
- ok_btn.setMinimumHeight(45)
- ok_btn.setMinimumWidth(100)
- ok_btn.setFont(QFont("微软雅黑", 16))
- ok_btn.clicked.connect(self.save)
-
- cancel_btn = QPushButton("取消")
- cancel_btn.setMinimumHeight(45)
- cancel_btn.setMinimumWidth(100)
- cancel_btn.setFont(QFont("微软雅黑", 16))
- cancel_btn.clicked.connect(self.reject)
-
- button_layout.addWidget(ok_btn)
- button_layout.addWidget(cancel_btn)
-
- layout.addLayout(button_layout)
- self.setLayout(layout)
-
- def save(self):
- """保存"""
- # 验证
- if not self.date_input.date().isValid():
- QMessageBox.warning(self, "验证失败", "请选择日期")
- return
-
- if not self.business_type_group.checkedButton():
- QMessageBox.warning(self, "验证失败", "请选择业务类型")
- return
-
- product = self.product_input.text().strip()
- if not product:
- QMessageBox.warning(self, "验证失败", "产品不能为空")
- return
-
- if self.quantity_input.value() <= 0:
- QMessageBox.warning(self, "验证失败", "计划量必须大于0")
- return
-
- vehicle_no = self.vehicle_input.text().strip()
- if not vehicle_no:
- QMessageBox.warning(self, "验证失败", "车牌号不能为空")
- return
-
- # 准备数据
- data = {
- 'plan_date': self.date_input.date().toString("yyyy-MM-dd"),
- 'business_type': self.business_type_group.checkedButton().text(),
- 'product': product,
- 'specification': self.spec_input.text().strip(),
- 'planned_quantity': self.quantity_input.value(),
- 'vehicle_no': vehicle_no,
- 'customer_name': self.customer_input.text().strip(),
- 'remarks': self.remarks_input.toPlainText().strip()
- }
-
- # 保存
- if self.plan:
- # 修改模式
- if self.db.update_purchase_plan(self.plan['id'], data):
- QMessageBox.information(self, "成功", "修改成功!")
- self.accept()
- else:
- QMessageBox.warning(self, "错误", "修改失败")
- else:
- # 新增模式
- try:
- self.db.insert_purchase_plan(data)
- QMessageBox.information(self, "成功", "新增成功!")
- self.accept()
- except Exception as e:
- QMessageBox.critical(self, "错误", f"新增失败:{str(e)}")
|