| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881 |
- """
- 地磅单管理Tab页面
- """
- from PyQt5.QtWidgets import (
- QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QComboBox,
- QRadioButton, QButtonGroup, QDateTimeEdit, QTextEdit, QPushButton,
- QTableWidget, QTableWidgetItem, QHeaderView, QMessageBox, QDialog,
- QFormLayout, QSplitter, QGroupBox, QDoubleSpinBox, QGridLayout
- )
- from PyQt5.QtCore import Qt, QDateTime, pyqtSignal, QTimer
- from PyQt5.QtGui import QFont, QColor, QKeyEvent, QKeySequence
- from datetime import datetime
- from typing import Tuple
- from database import Database
- from utils.printer import Printer
- class EmptyDoubleSpinBox(QDoubleSpinBox):
- """自定义QDoubleSpinBox,当值为-1时显示为空"""
-
- def textFromValue(self, value: float) -> str:
- """重写文本显示方法,当值为-1时返回空字符串"""
- if value == -1:
- return ""
- return super().textFromValue(value)
-
- def valueFromText(self, text: str) -> float:
- """重写文本解析方法,当文本为空时返回-1"""
- if not text or text.strip() == "":
- return -1
- return super().valueFromText(text)
- class EmptyDateTimeEdit(QDateTimeEdit):
- """自定义QDateTimeEdit,当日期时间为无效时显示为空"""
-
- def __init__(self, parent=None):
- super().__init__(parent)
- # 监听日期时间变化,自动更新显示
- self.dateTimeChanged.connect(self._update_display)
- # 设置一个无效的默认日期时间
- from PyQt5.QtCore import QDateTime
- super().setDateTime(QDateTime())
-
- def _update_display(self):
- """更新显示,如果日期时间无效则显示为空"""
- try:
- if not self.dateTime().isValid():
- line_edit = self.lineEdit()
- if line_edit:
- line_edit.setText("")
- except:
- pass
-
- def setDateTime(self, dateTime: QDateTime):
- """重写设置日期时间方法"""
- super().setDateTime(dateTime)
- # 延迟更新显示,确保控件已完全初始化
- if not dateTime.isValid():
- QTimer.singleShot(0, self._update_display)
- # 立即清空显示
- line_edit = self.lineEdit()
- if line_edit:
- line_edit.setText("")
-
- def showEvent(self, event):
- """重写显示事件,确保在显示时也清空"""
- super().showEvent(event)
- # 延迟更新显示,确保控件已完全初始化
- if not self.dateTime().isValid():
- QTimer.singleShot(0, self._update_display)
- class WeighingTab(QWidget):
- """地磅单管理Tab"""
-
- def __init__(self, db: Database):
- super().__init__()
- self.db = db
- self.printer = Printer()
- self.init_ui()
- self.refresh_dropdowns()
- self.refresh_list()
-
- def init_ui(self):
- """初始化界面"""
- layout = QVBoxLayout()
- layout.setSpacing(10)
- layout.setContentsMargins(10, 10, 10, 10)
-
- # 创建分割器,用于调整上下两部分的大小
- splitter = QSplitter(Qt.Vertical)
-
- # 上部分:地磅单填写模块(占据65%空间)
- form_widget = self.create_form_widget()
- splitter.addWidget(form_widget)
-
- # 下部分:地磅单记录列表(占据35%空间)
- list_widget = self.create_list_widget()
- splitter.addWidget(list_widget)
-
- # 设置分割比例(65:35)
- splitter.setSizes([650, 350])
-
- layout.addWidget(splitter)
- self.setLayout(layout)
-
- def create_form_widget(self) -> QWidget:
- """创建地磅单填写表单"""
- widget = QWidget()
- layout = QVBoxLayout()
- layout.setSpacing(15)
- layout.setContentsMargins(15, 15, 15, 15)
-
- # 标题
- title = QLabel("地磅单填写")
- title_font = QFont("微软雅黑", 18, QFont.Bold)
- title.setFont(title_font)
- layout.addWidget(title)
-
- # 表单区域 - 使用网格布局,一行放4个元素(2对字段)
- form_layout = QGridLayout()
- form_layout.setSpacing(15)
- form_layout.setColumnStretch(1, 1) # 第2列(控件列)可拉伸
- form_layout.setColumnStretch(3, 1) # 第4列(控件列)可拉伸
-
- # 创建控件
- # 必填字段在前,非必填字段在后
- # 必填字段label为红色,非必填字段label为黑色
- row = 0
-
- # 第一行:车号(必填)、货物名称(必填)、业务类型(必填)、供货单位(必填)
- # 车号(必填)
- vehicle_label = QLabel("<span style='color: red;'>车号 *</span>:")
- vehicle_label.setFont(QFont("微软雅黑", 16))
- vehicle_label.setTextFormat(Qt.RichText)
- self.vehicle_no_input = QLineEdit()
- self.vehicle_no_input.setMinimumHeight(40)
- self.vehicle_no_input.setFont(QFont("微软雅黑", 16))
- form_layout.addWidget(vehicle_label, row, 0)
- form_layout.addWidget(self.vehicle_no_input, row, 1)
-
- # 货物名称(必填)
- cargo_label = QLabel("<span style='color: red;'>货物名称 *</span>:")
- cargo_label.setFont(QFont("微软雅黑", 16))
- cargo_label.setTextFormat(Qt.RichText)
- self.cargo_combo = QComboBox()
- self.cargo_combo.setMinimumHeight(40)
- self.cargo_combo.setFont(QFont("微软雅黑", 16))
- self.cargo_combo.setEditable(False)
- form_layout.addWidget(cargo_label, row, 2)
- form_layout.addWidget(self.cargo_combo, row, 3)
-
- row += 1
-
- # 第二行:业务类型(必填)、供货单位(必填)、收货单位(必填)
- # 业务类型(必填)
- business_label = QLabel("<span style='color: red;'>业务类型 *</span>:")
- business_label.setFont(QFont("微软雅黑", 16))
- business_label.setTextFormat(Qt.RichText)
- 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.addWidget(business_label, row, 0)
- form_layout.addWidget(business_widget, row, 1)
-
- # 供货单位(必填)
- supplier_label = QLabel("<span style='color: red;'>供货单位 *</span>:")
- supplier_label.setFont(QFont("微软雅黑", 16))
- supplier_label.setTextFormat(Qt.RichText)
- self.supplier_combo = QComboBox()
- self.supplier_combo.setMinimumHeight(40)
- self.supplier_combo.setFont(QFont("微软雅黑", 16))
- self.supplier_combo.setEditable(False)
- form_layout.addWidget(supplier_label, row, 2)
- form_layout.addWidget(self.supplier_combo, row, 3)
-
- row += 1
-
- # 第三行:收货单位(必填)、毛重(kg)(必填)、毛重时间(必填)、皮重(kg)(必填)
- # 收货单位(必填)
- consignee_label = QLabel("<span style='color: red;'>收货单位 *</span>:")
- consignee_label.setFont(QFont("微软雅黑", 16))
- consignee_label.setTextFormat(Qt.RichText)
- self.consignee_combo = QComboBox()
- self.consignee_combo.setMinimumHeight(40)
- self.consignee_combo.setFont(QFont("微软雅黑", 16))
- self.consignee_combo.setEditable(False)
- form_layout.addWidget(consignee_label, row, 0)
- form_layout.addWidget(self.consignee_combo, row, 1)
-
- # 毛重(kg)(必填)
- gross_weight_label = QLabel("<span style='color: red;'>毛重(kg) *</span>:")
- gross_weight_label.setFont(QFont("微软雅黑", 16))
- gross_weight_label.setTextFormat(Qt.RichText)
- self.gross_weight_input = EmptyDoubleSpinBox()
- self.gross_weight_input.setMinimumHeight(40)
- self.gross_weight_input.setFont(QFont("微软雅黑", 16))
- self.gross_weight_input.setDecimals(2)
- self.gross_weight_input.setMinimum(-1)
- self.gross_weight_input.setMaximum(999999)
- self.gross_weight_input.setSpecialValueText("")
- self.gross_weight_input.setValue(-1)
- form_layout.addWidget(gross_weight_label, row, 2)
- form_layout.addWidget(self.gross_weight_input, row, 3)
-
- row += 1
-
- # 第四行:毛重时间(必填)、皮重(kg)(必填)、皮重时间(必填)
- # 毛重时间(必填)
- gross_time_label = QLabel("<span style='color: red;'>毛重时间 *</span>:")
- gross_time_label.setFont(QFont("微软雅黑", 16))
- gross_time_label.setTextFormat(Qt.RichText)
- self.gross_weight_time = EmptyDateTimeEdit()
- self.gross_weight_time.setMinimumHeight(40)
- self.gross_weight_time.setFont(QFont("微软雅黑", 16))
- self.gross_weight_time.setCalendarPopup(True)
- # 不设置默认时间,使用一个无效的日期时间表示未设置
- self.gross_weight_time.setDateTime(QDateTime())
- self.gross_weight_time.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
- # 强制清空显示
- if self.gross_weight_time.lineEdit():
- self.gross_weight_time.lineEdit().setText("")
- QTimer.singleShot(0, lambda: self.gross_weight_time.lineEdit().setText("") if self.gross_weight_time.lineEdit() else None)
- # 创建获取当前时间按钮
- gross_time_btn = QPushButton("获取当前时间")
- gross_time_btn.setMinimumHeight(40)
- gross_time_btn.setFont(QFont("微软雅黑", 14))
- gross_time_btn.clicked.connect(lambda: self.gross_weight_time.setDateTime(QDateTime.currentDateTime()))
- gross_time_layout = QHBoxLayout()
- gross_time_layout.addWidget(self.gross_weight_time)
- gross_time_layout.addWidget(gross_time_btn)
- gross_time_layout.setContentsMargins(0, 0, 0, 0)
- gross_time_widget = QWidget()
- gross_time_widget.setLayout(gross_time_layout)
- form_layout.addWidget(gross_time_label, row, 0)
- form_layout.addWidget(gross_time_widget, row, 1)
-
- # 皮重(kg)(必填)
- tare_weight_label = QLabel("<span style='color: red;'>皮重(kg) *</span>:")
- tare_weight_label.setFont(QFont("微软雅黑", 16))
- tare_weight_label.setTextFormat(Qt.RichText)
- self.tare_weight_input = EmptyDoubleSpinBox()
- self.tare_weight_input.setMinimumHeight(40)
- self.tare_weight_input.setFont(QFont("微软雅黑", 16))
- self.tare_weight_input.setDecimals(2)
- self.tare_weight_input.setMinimum(-1)
- self.tare_weight_input.setMaximum(999999)
- self.tare_weight_input.setSpecialValueText("")
- self.tare_weight_input.setValue(-1)
- form_layout.addWidget(tare_weight_label, row, 2)
- form_layout.addWidget(self.tare_weight_input, row, 3)
-
- row += 1
-
- # 第五行:皮重时间(必填)
- # 皮重时间(必填)
- tare_time_label = QLabel("<span style='color: red;'>皮重时间 *</span>:")
- tare_time_label.setFont(QFont("微软雅黑", 16))
- tare_time_label.setTextFormat(Qt.RichText)
- self.tare_weight_time = EmptyDateTimeEdit()
- self.tare_weight_time.setMinimumHeight(40)
- self.tare_weight_time.setFont(QFont("微软雅黑", 16))
- self.tare_weight_time.setCalendarPopup(True)
- # 不设置默认时间,使用一个无效的日期时间表示未设置
- self.tare_weight_time.setDateTime(QDateTime())
- self.tare_weight_time.setDisplayFormat("yyyy-MM-dd HH:mm:ss")
- # 强制清空显示
- if self.tare_weight_time.lineEdit():
- self.tare_weight_time.lineEdit().setText("")
- QTimer.singleShot(0, lambda: self.tare_weight_time.lineEdit().setText("") if self.tare_weight_time.lineEdit() else None)
- # 创建获取当前时间按钮
- tare_time_btn = QPushButton("获取当前时间")
- tare_time_btn.setMinimumHeight(40)
- tare_time_btn.setFont(QFont("微软雅黑", 14))
- tare_time_btn.clicked.connect(lambda: self.tare_weight_time.setDateTime(QDateTime.currentDateTime()))
- tare_time_layout = QHBoxLayout()
- tare_time_layout.addWidget(self.tare_weight_time)
- tare_time_layout.addWidget(tare_time_btn)
- tare_time_layout.setContentsMargins(0, 0, 0, 0)
- tare_time_widget = QWidget()
- tare_time_widget.setLayout(tare_time_layout)
- form_layout.addWidget(tare_time_label, row, 0)
- form_layout.addWidget(tare_time_widget, row, 1)
-
- row += 1
-
- # 非必填字段开始
- # 第六行:计划号(非必填)、批号(非必填)、扣杂(kg)、净重(kg)(自动计算,只读)
- # 计划号(非必填)
- plan_label = QLabel("计划号:")
- plan_label.setFont(QFont("微软雅黑", 16))
- self.plan_no_input = QLineEdit()
- self.plan_no_input.setMinimumHeight(40)
- self.plan_no_input.setFont(QFont("微软雅黑", 16))
- form_layout.addWidget(plan_label, row, 0)
- form_layout.addWidget(self.plan_no_input, row, 1)
-
- # 批号(非必填)
- batch_label = QLabel("批号:")
- batch_label.setFont(QFont("微软雅黑", 16))
- self.batch_no_input = QLineEdit()
- self.batch_no_input.setMinimumHeight(40)
- self.batch_no_input.setFont(QFont("微软雅黑", 16))
- form_layout.addWidget(batch_label, row, 2)
- form_layout.addWidget(self.batch_no_input, row, 3)
-
- row += 1
-
- # 第七行:扣杂(kg)、净重(kg)(自动计算,只读)、计划量(kg)、已执行量(kg)
- # 扣杂(kg)
- deduction_label = QLabel("扣杂(kg):")
- deduction_label.setFont(QFont("微软雅黑", 16))
- self.deduction_input = EmptyDoubleSpinBox()
- self.deduction_input.setMinimumHeight(40)
- self.deduction_input.setFont(QFont("微软雅黑", 16))
- self.deduction_input.setDecimals(2)
- self.deduction_input.setMinimum(-1)
- self.deduction_input.setMaximum(999999)
- self.deduction_input.setSpecialValueText("")
- self.deduction_input.setValue(-1)
- self.deduction_input.valueChanged.connect(self.calculate_net_weight)
- self.gross_weight_input.valueChanged.connect(self.calculate_net_weight)
- self.tare_weight_input.valueChanged.connect(self.calculate_net_weight)
- form_layout.addWidget(deduction_label, row, 0)
- form_layout.addWidget(self.deduction_input, row, 1)
-
- # 净重(kg)(自动计算,只读)
- net_weight_label = QLabel("净重(kg):")
- net_weight_label.setFont(QFont("微软雅黑", 16))
- self.net_weight_label = QLabel("0.000 kg")
- self.net_weight_label.setMinimumHeight(40)
- self.net_weight_label.setFont(QFont("微软雅黑", 16))
- self.net_weight_label.setStyleSheet("background-color: #f0f0f0; padding: 5px; border: 1px solid #ccc;")
- form_layout.addWidget(net_weight_label, row, 2)
- form_layout.addWidget(self.net_weight_label, row, 3)
-
- row += 1
-
- # 第八行:计划量(kg)、已执行量(kg)
- # 计划量(kg)
- planned_label = QLabel("计划量(kg):")
- planned_label.setFont(QFont("微软雅黑", 16))
- self.planned_quantity_input = EmptyDoubleSpinBox()
- self.planned_quantity_input.setMinimumHeight(40)
- self.planned_quantity_input.setFont(QFont("微软雅黑", 16))
- self.planned_quantity_input.setDecimals(2)
- self.planned_quantity_input.setMinimum(-1)
- self.planned_quantity_input.setMaximum(999999)
- self.planned_quantity_input.setSpecialValueText("")
- self.planned_quantity_input.setValue(-1)
- form_layout.addWidget(planned_label, row, 0)
- form_layout.addWidget(self.planned_quantity_input, row, 1)
-
- # 已执行量(kg)
- executed_label = QLabel("已执行量(kg):")
- executed_label.setFont(QFont("微软雅黑", 16))
- self.executed_quantity_input = EmptyDoubleSpinBox()
- self.executed_quantity_input.setMinimumHeight(40)
- self.executed_quantity_input.setFont(QFont("微软雅黑", 16))
- self.executed_quantity_input.setDecimals(2)
- self.executed_quantity_input.setMinimum(-1)
- self.executed_quantity_input.setMaximum(999999)
- self.executed_quantity_input.setSpecialValueText("")
- self.executed_quantity_input.setValue(-1)
- form_layout.addWidget(executed_label, row, 2)
- form_layout.addWidget(self.executed_quantity_input, row, 3)
-
- row += 1
-
- # 第九行:备注(跨4列)
- 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.addWidget(remarks_label, row, 0)
- form_layout.addWidget(self.remarks_input, row, 1, 1, 3) # 跨3列
-
- # 按钮区域
- row += 1
- button_layout = QHBoxLayout()
- button_layout.addStretch()
-
- self.save_btn = QPushButton("保存")
- self.save_btn.setMinimumHeight(45)
- self.save_btn.setMinimumWidth(120)
- self.save_btn.setFont(QFont("微软雅黑", 16, QFont.Bold))
- self.save_btn.setStyleSheet("background-color: #2196F3; color: white; border-radius: 5px;")
- self.save_btn.clicked.connect(self.save_weighing_slip)
- # 添加快捷键
- self.save_btn.setShortcut(QKeySequence("Ctrl+S"))
-
- self.clear_btn = QPushButton("清空")
- self.clear_btn.setMinimumHeight(45)
- self.clear_btn.setMinimumWidth(120)
- self.clear_btn.setFont(QFont("微软雅黑", 16))
- self.clear_btn.setStyleSheet("background-color: #757575; color: white; border-radius: 5px;")
- self.clear_btn.clicked.connect(self.clear_form)
-
- button_layout.addWidget(self.save_btn)
- button_layout.addWidget(self.clear_btn)
- button_layout.addStretch()
-
- button_widget = QWidget()
- button_widget.setLayout(button_layout)
- form_layout.addWidget(button_widget, row, 0, 1, 4) # 跨4列
-
- # 将表单布局添加到主布局
- layout.addLayout(form_layout)
-
- # 包装在GroupBox中
- group_box = QGroupBox()
- group_box.setLayout(layout)
-
- return group_box
-
- def create_list_widget(self) -> QWidget:
- """创建地磅单记录列表"""
- widget = QWidget()
- layout = QVBoxLayout()
- layout.setContentsMargins(10, 10, 10, 10)
-
- # 标题和刷新按钮区域
- title_layout = QHBoxLayout()
- title = QLabel("地磅单记录列表")
- title_font = QFont("微软雅黑", 18, QFont.Bold)
- title.setFont(title_font)
- title_layout.addWidget(title)
- title_layout.addStretch()
-
- self.refresh_btn = QPushButton("刷新")
- self.refresh_btn.setMinimumHeight(40)
- self.refresh_btn.setMinimumWidth(100)
- 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"))
- title_layout.addWidget(self.refresh_btn)
-
- layout.addLayout(title_layout)
-
- # 表格
- self.table = QTableWidget()
- self.table.setColumnCount(7)
- self.table.setHorizontalHeaderLabels(["序号", "车号", "货物名称", "业务类型", "净重(kg)", "毛重时间", "操作"])
- 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)
-
- layout.addWidget(self.table)
-
- widget.setLayout(layout)
- return widget
-
- def calculate_net_weight(self):
- """计算净重"""
- gross = self.gross_weight_input.value() if self.gross_weight_input.value() >= 0 else 0
- tare = self.tare_weight_input.value() if self.tare_weight_input.value() >= 0 else 0
- deduction = self.deduction_input.value() if self.deduction_input.value() >= 0 else 0
- net = gross - tare - deduction
- self.net_weight_label.setText(f"{net:.2f} kg")
-
- def refresh_dropdowns(self):
- """刷新下拉列表"""
- # 刷新货物名称
- self.cargo_combo.clear()
- self.cargo_combo.addItem("") # 添加一个空选项
- cargos = self.db.get_all_cargos()
- for cargo in cargos:
- self.cargo_combo.addItem(cargo['name'])
- self.cargo_combo.setCurrentIndex(0) # 默认选中空选项
-
- # 刷新公司名称(供货单位和收货单位共用)
- self.supplier_combo.clear()
- self.supplier_combo.addItem("") # 添加一个空选项
- self.consignee_combo.clear()
- self.consignee_combo.addItem("") # 添加一个空选项
- companies = self.db.get_all_companies()
- for company in companies:
- self.supplier_combo.addItem(company['name'])
- self.consignee_combo.addItem(company['name'])
- self.supplier_combo.setCurrentIndex(0) # 默认选中空选项
- self.consignee_combo.setCurrentIndex(0) # 默认选中空选项
-
- def refresh_list(self):
- """刷新地磅单记录列表"""
- slips = self.db.get_all_weighing_slips()
- self.table.setRowCount(len(slips))
-
- for i, slip in enumerate(slips):
- # 序号
- self.table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
-
- # 车号
- self.table.setItem(i, 1, QTableWidgetItem(slip['vehicle_no']))
-
- # 货物名称
- self.table.setItem(i, 2, QTableWidgetItem(slip['cargo_name']))
-
- # 业务类型
- self.table.setItem(i, 3, QTableWidgetItem(slip['business_type']))
-
- # 净重
- if slip['is_voided']:
- net_weight_item = QTableWidgetItem("[作废]")
- net_weight_item.setForeground(QColor(128, 128, 128))
- else:
- net_weight_item = QTableWidgetItem(f"{slip['net_weight']:.2f}")
- self.table.setItem(i, 4, net_weight_item)
-
- # 毛重时间
- self.table.setItem(i, 5, QTableWidgetItem(slip['gross_weight_time']))
-
- # 操作按钮
- btn_widget = QWidget()
- btn_layout = QHBoxLayout()
- btn_layout.setContentsMargins(5, 2, 5, 2)
-
- detail_btn = QPushButton("查看")
- detail_btn.setFont(QFont("微软雅黑", 14))
- detail_btn.clicked.connect(lambda checked, sid=slip['id']: self.show_detail(sid))
-
- preview_btn = QPushButton("打印")
- preview_btn.setFont(QFont("微软雅黑", 14))
- preview_btn.clicked.connect(lambda checked, sid=slip['id']: self.preview_slip(sid))
-
- void_btn = QPushButton("作废")
- void_btn.setFont(QFont("微软雅黑", 14))
- void_btn.setStyleSheet("background-color: #f44336; color: white;")
- void_btn.clicked.connect(lambda checked, sid=slip['id']: self.void_slip(sid))
-
- if slip['is_voided']:
- void_btn.setEnabled(False)
- void_btn.setText("已作废")
-
- btn_layout.addWidget(detail_btn)
- btn_layout.addWidget(preview_btn)
- btn_layout.addWidget(void_btn)
- btn_widget.setLayout(btn_layout)
-
- self.table.setCellWidget(i, 6, btn_widget)
-
- # 如果已作废,整行灰色显示
- if slip['is_voided']:
- for j in range(self.table.columnCount()):
- item = self.table.item(i, j)
- if item:
- item.setBackground(QColor(240, 240, 240))
-
- self.table.resizeRowsToContents()
-
- def validate_form(self) -> Tuple[bool, str]:
- """验证表单数据"""
- # 清除之前的错误样式
- self.clear_error_styles()
-
- if not self.vehicle_no_input.text().strip():
- self.set_error_style(self.vehicle_no_input)
- return False, "请填写车号"
-
- if self.cargo_combo.currentIndex() <= 0 or not self.cargo_combo.currentText().strip():
- self.set_error_style(self.cargo_combo)
- return False, "请选择货物名称"
-
- if not self.business_type_group.checkedButton():
- return False, "请选择业务类型"
-
- if self.supplier_combo.currentIndex() <= 0 or not self.supplier_combo.currentText().strip():
- self.set_error_style(self.supplier_combo)
- return False, "请选择供货单位"
-
- if self.consignee_combo.currentIndex() <= 0 or not self.consignee_combo.currentText().strip():
- self.set_error_style(self.consignee_combo)
- return False, "请选择收货单位"
-
- if self.gross_weight_input.value() < 0:
- self.set_error_style(self.gross_weight_input)
- return False, "请填写毛重"
-
- if self.gross_weight_input.value() <= 0:
- self.set_error_style(self.gross_weight_input)
- return False, "毛重必须大于0"
-
- if self.tare_weight_input.value() < 0:
- self.set_error_style(self.tare_weight_input)
- return False, "请填写皮重"
-
- if self.tare_weight_input.value() <= 0:
- self.set_error_style(self.tare_weight_input)
- return False, "皮重必须大于0"
-
- # 验证毛重时间:检查日期时间是否有效,同时检查文本是否为空
- gross_time_text = self.gross_weight_time.lineEdit().text().strip() if self.gross_weight_time.lineEdit() else ""
- if not self.gross_weight_time.dateTime().isValid() or not gross_time_text:
- self.set_error_style(self.gross_weight_time)
- return False, "请填写毛重时间"
-
- # 验证皮重时间:检查日期时间是否有效,同时检查文本是否为空
- tare_time_text = self.tare_weight_time.lineEdit().text().strip() if self.tare_weight_time.lineEdit() else ""
- if not self.tare_weight_time.dateTime().isValid() or not tare_time_text:
- self.set_error_style(self.tare_weight_time)
- return False, "请填写皮重时间"
-
- # 计算净重
- gross = self.gross_weight_input.value()
- tare = self.tare_weight_input.value()
- deduction = self.deduction_input.value() if self.deduction_input.value() >= 0 else 0
- net_weight = gross - tare - deduction
- if net_weight <= 0:
- return False, "净重必须大于0,请检查毛重、皮重和扣杂的数值"
-
- return True, ""
-
- def set_error_style(self, widget):
- """设置错误样式(红色边框)"""
- widget.setStyleSheet("border: 2px solid red;")
-
- def clear_error_styles(self):
- """清除所有错误样式"""
- self.vehicle_no_input.setStyleSheet("")
- self.cargo_combo.setStyleSheet("")
- self.supplier_combo.setStyleSheet("")
- self.consignee_combo.setStyleSheet("")
- self.gross_weight_input.setStyleSheet("")
- self.tare_weight_input.setStyleSheet("")
- self.gross_weight_time.setStyleSheet("")
- self.tare_weight_time.setStyleSheet("")
-
- def save_weighing_slip(self):
- """保存地磅单"""
- # 验证
- valid, error_msg = self.validate_form()
- if not valid:
- QMessageBox.warning(self, "验证失败", error_msg)
- return
-
- # 准备数据
- data = {
- 'vehicle_no': self.vehicle_no_input.text().strip(),
- 'plan_no': self.plan_no_input.text().strip(),
- 'cargo_name': self.cargo_combo.currentText(),
- 'business_type': self.business_type_group.checkedButton().text(),
- 'batch_no': self.batch_no_input.text().strip(),
- 'supplier': self.supplier_combo.currentText(),
- 'consignee': self.consignee_combo.currentText(),
- 'gross_weight': self.gross_weight_input.value(),
- 'gross_weight_time': self.gross_weight_time.dateTime().toString("yyyy-MM-dd HH:mm:ss") if self.gross_weight_time.dateTime().isValid() else "",
- 'tare_weight': self.tare_weight_input.value(),
- 'tare_weight_time': self.tare_weight_time.dateTime().toString("yyyy-MM-dd HH:mm:ss") if self.tare_weight_time.dateTime().isValid() else "",
- 'deduction': self.deduction_input.value() if self.deduction_input.value() >= 0 else 0,
- 'planned_quantity': self.planned_quantity_input.value() if self.planned_quantity_input.value() >= 0 else None,
- 'executed_quantity': self.executed_quantity_input.value() if self.executed_quantity_input.value() >= 0 else None,
- 'remarks': self.remarks_input.toPlainText().strip()
- }
-
- try:
- self.db.insert_weighing_slip(data)
- QMessageBox.information(self, "成功", "地磅单保存成功!")
- self.clear_error_styles() # 清除错误样式
- self.clear_form()
- self.refresh_list()
- except Exception as e:
- QMessageBox.critical(self, "错误", f"保存失败:{str(e)}")
-
- def clear_form(self):
- """清空表单"""
- self.vehicle_no_input.clear()
- self.plan_no_input.clear()
- # 清空货物名称、供货单位、收货单位(设置为第一个空选项)
- if self.cargo_combo.count() > 0:
- self.cargo_combo.setCurrentIndex(0)
- if self.supplier_combo.count() > 0:
- self.supplier_combo.setCurrentIndex(0)
- if self.consignee_combo.count() > 0:
- self.consignee_combo.setCurrentIndex(0)
- # 不设置业务类型默认选中
- if self.business_type_group.checkedButton():
- self.business_type_group.setExclusive(False)
- self.business_type_group.checkedButton().setChecked(False)
- self.business_type_group.setExclusive(True)
- self.batch_no_input.clear()
- self.gross_weight_input.setValue(-1)
- # 不设置毛重时间默认值,使用无效日期时间
- self.gross_weight_time.setDateTime(QDateTime())
- if self.gross_weight_time.lineEdit():
- self.gross_weight_time.lineEdit().setText("")
- # 延迟清空,确保显示被正确清空
- QTimer.singleShot(0, lambda: self.gross_weight_time.lineEdit().setText("") if self.gross_weight_time.lineEdit() else None)
- self.tare_weight_input.setValue(-1)
- # 不设置皮重时间默认值,使用无效日期时间
- self.tare_weight_time.setDateTime(QDateTime())
- if self.tare_weight_time.lineEdit():
- self.tare_weight_time.lineEdit().setText("")
- # 延迟清空,确保显示被正确清空
- QTimer.singleShot(0, lambda: self.tare_weight_time.lineEdit().setText("") if self.tare_weight_time.lineEdit() else None)
- self.deduction_input.setValue(-1)
- self.net_weight_label.setText("0.00 kg")
- self.planned_quantity_input.setValue(-1)
- self.executed_quantity_input.setValue(-1)
- self.remarks_input.clear()
-
- def show_detail(self, slip_id: int):
- """显示地磅单详情"""
- slip = self.db.get_weighing_slip_by_id(slip_id)
- if not slip:
- QMessageBox.warning(self, "错误", "未找到该地磅单")
- return
-
- dialog = DetailDialog(slip, self.db, self)
- dialog.exec_()
-
- def preview_slip(self, slip_id: int):
- """预览地磅单"""
- slip = self.db.get_weighing_slip_by_id(slip_id)
- if not slip:
- QMessageBox.warning(self, "错误", "未找到该地磅单")
- return
-
- try:
- self.printer.preview_weighing_slip(slip)
- except Exception as e:
- QMessageBox.critical(self, "错误", f"预览失败:{str(e)}")
-
- def print_slip(self, slip_id: int):
- """打印地磅单"""
- slip = self.db.get_weighing_slip_by_id(slip_id)
- if not slip:
- QMessageBox.warning(self, "错误", "未找到该地磅单")
- return
-
- try:
- self.printer.print_weighing_slip(slip)
- QMessageBox.information(self, "成功", "打印任务已发送")
- except Exception as e:
- QMessageBox.critical(self, "错误", f"打印失败:{str(e)}")
-
- def void_slip(self, slip_id: int):
- """作废地磅单"""
- reply = QMessageBox.question(
- self, "确认", "确定要作废这条地磅单吗?",
- QMessageBox.Yes | QMessageBox.No,
- QMessageBox.No
- )
-
- if reply == QMessageBox.Yes:
- if self.db.void_weighing_slip(slip_id):
- QMessageBox.information(self, "成功", "地磅单已作废")
- self.refresh_list()
- else:
- QMessageBox.warning(self, "错误", "作废失败")
- class DetailDialog(QDialog):
- """地磅单详情对话框"""
-
- def __init__(self, slip: dict, db: Database, parent=None):
- super().__init__(parent)
- self.slip = slip
- self.db = db
- self.printer = Printer()
- self.init_ui()
-
- def init_ui(self):
- """初始化对话框界面"""
- self.setWindowTitle("地磅单详情")
- self.setMinimumWidth(500)
-
- layout = QVBoxLayout()
- layout.setSpacing(10)
- layout.setContentsMargins(20, 20, 20, 20)
-
- # 显示详情信息(只读)
- form_layout = QFormLayout()
- form_layout.setSpacing(10)
- label_font = QFont("微软雅黑", 16)
-
- fields = [
- ("车号", self.slip['vehicle_no']),
- ("计划号", self.slip.get('plan_no', '')),
- ("货物名称", self.slip['cargo_name']),
- ("业务类型", self.slip['business_type']),
- ("批号", self.slip.get('batch_no', '')),
- ("供货单位", self.slip['supplier']),
- ("收货单位", self.slip['consignee']),
- ("毛重(kg)", f"{self.slip['gross_weight']:.2f}"),
- ("毛重时间", self.slip['gross_weight_time']),
- ("皮重(kg)", f"{self.slip['tare_weight']:.2f}"),
- ("皮重时间", self.slip['tare_weight_time']),
- ("扣杂(kg)", f"{self.slip.get('deduction', 0):.2f}"),
- ("净重(kg)", f"{self.slip['net_weight']:.2f}"),
- ("计划量(kg)", f"{self.slip.get('planned_quantity', 0):.2f}" if self.slip.get('planned_quantity') else ""),
- ("已执行量(kg)", f"{self.slip.get('executed_quantity', 0):.2f}" if self.slip.get('executed_quantity') else ""),
- ("磅点", self.slip.get('weighing_point', '山峡地磅')),
- ("备注", self.slip.get('remarks', ''))
- ]
-
- for label, value in fields:
- label_widget = QLabel(f"{label}:")
- label_widget.setFont(label_font)
- value_label = QLabel(str(value) if value else "")
- value_label.setFont(QFont("微软雅黑", 15))
- form_layout.addRow(label_widget, value_label)
-
- layout.addLayout(form_layout)
-
- # 按钮
- button_layout = QHBoxLayout()
- button_layout.addStretch()
-
- preview_btn = QPushButton("预览")
- preview_btn.setMinimumHeight(40)
- preview_btn.setMinimumWidth(100)
- preview_btn.setFont(QFont("微软雅黑", 15))
- preview_btn.clicked.connect(self.preview_slip)
-
- print_btn = QPushButton("打印")
- print_btn.setMinimumHeight(40)
- print_btn.setMinimumWidth(100)
- print_btn.setFont(QFont("微软雅黑", 15))
- print_btn.clicked.connect(self.print_slip)
-
- close_btn = QPushButton("关闭")
- close_btn.setMinimumHeight(40)
- close_btn.setMinimumWidth(100)
- close_btn.setFont(QFont("微软雅黑", 15))
- close_btn.clicked.connect(self.accept)
-
- button_layout.addWidget(preview_btn)
- button_layout.addWidget(print_btn)
- button_layout.addWidget(close_btn)
-
- layout.addLayout(button_layout)
- self.setLayout(layout)
-
- def preview_slip(self):
- """预览地磅单"""
- try:
- self.printer.preview_weighing_slip(self.slip)
- except Exception as e:
- QMessageBox.critical(self, "错误", f"预览失败:{str(e)}")
-
- def print_slip(self):
- """打印地磅单"""
- try:
- self.printer.print_weighing_slip(self.slip)
- QMessageBox.information(self, "成功", "打印任务已发送")
- except Exception as e:
- QMessageBox.critical(self, "错误", f"打印失败:{str(e)}")
|