脚本优化 工序名称查询条件优化
parent
c73d347e01
commit
da0e41f475
210
ui_main.py
210
ui_main.py
|
|
@ -1196,6 +1196,30 @@ class MainWindow(QMainWindow):
|
|||
self.start_work_order_btn.clicked.connect(self._start_work_order)
|
||||
toolbar_layout.addWidget(self.start_work_order_btn)
|
||||
|
||||
# 实验台上电按钮
|
||||
self.power_on_btn = QPushButton("实验台上电")
|
||||
self.power_on_btn.setStyleSheet(
|
||||
"QPushButton { font-weight:700; font-size:13px; color:white;"
|
||||
"padding:8px 20px; border-radius:6px; background-color:#4caf50; }"
|
||||
"QPushButton:hover { background-color:#388e3c; }"
|
||||
)
|
||||
self.power_on_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.power_on_btn.setFixedHeight(36)
|
||||
self.power_on_btn.clicked.connect(self._power_on_experiment_table)
|
||||
toolbar_layout.addWidget(self.power_on_btn)
|
||||
|
||||
# 实验台断电按钮
|
||||
self.power_off_btn = QPushButton("实验台断电")
|
||||
self.power_off_btn.setStyleSheet(
|
||||
"QPushButton { font-weight:700; font-size:13px; color:white;"
|
||||
"padding:8px 20px; border-radius:6px; background-color:#f44336; }"
|
||||
"QPushButton:hover { background-color:#d32f2f; }"
|
||||
)
|
||||
self.power_off_btn.setCursor(Qt.PointingHandCursor)
|
||||
self.power_off_btn.setFixedHeight(36)
|
||||
self.power_off_btn.clicked.connect(self._power_off_experiment_table)
|
||||
toolbar_layout.addWidget(self.power_off_btn)
|
||||
|
||||
# 开始记录按钮(仅Debug模式显示)
|
||||
self.start_exp_btn = QPushButton("开始记录")
|
||||
self.start_exp_btn.setStyleSheet(
|
||||
|
|
@ -4441,21 +4465,42 @@ class MainWindow(QMainWindow):
|
|||
self.logger.error(f"Failed to delete abandoned experiment record: {e}")
|
||||
# 只有当最新的记录未结束时才提示
|
||||
elif end_ts is None:
|
||||
# 若用户此时关闭程序,视为本次实验“非正常终止”,应标记为作废
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"实验记录未结束",
|
||||
f"检测到最新的实验记录未结束(开始时间: {start_ts})\n\n是否结束当前实验记录并关闭程序?",
|
||||
f"检测到最新的实验记录未结束(开始时间: {start_ts})\n\n"
|
||||
"关闭程序将把该实验记录标记为【作废】。\n\n"
|
||||
"是否继续并作废该实验记录?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
# 用户确认结束实验
|
||||
# 用户确认关闭:将该实验标记为作废,而不是已完成
|
||||
try:
|
||||
self._end_experiment()
|
||||
self.logger.info("Experiment ended before closing application")
|
||||
db = sqlite3.connect(str(APP_DIR / "experiments.db"))
|
||||
cur = db.cursor()
|
||||
cur.execute(
|
||||
"""
|
||||
UPDATE experiments
|
||||
SET
|
||||
end_ts = COALESCE(end_ts, datetime('now')),
|
||||
is_terminated = 1,
|
||||
remark = CASE
|
||||
WHEN remark IS NULL OR remark = '' THEN '作废-手动关闭程序'
|
||||
WHEN remark LIKE '%作废-手动关闭程序%' THEN remark
|
||||
ELSE remark || ' [作废-手动关闭程序]'
|
||||
END
|
||||
WHERE id = ?
|
||||
""",
|
||||
(eid,),
|
||||
)
|
||||
db.commit()
|
||||
db.close()
|
||||
self.logger.info(f"[关闭程序] 实验 {eid} 在窗口关闭时被标记为作废")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Failed to end experiment: {e}")
|
||||
self.logger.error(f"[关闭程序] 标记实验为作废失败: {e}")
|
||||
event.accept()
|
||||
else:
|
||||
# 用户取消关闭
|
||||
|
|
@ -5356,12 +5401,94 @@ class MainWindow(QMainWindow):
|
|||
except Exception as e:
|
||||
self.logger.error(f"[UI更新] 处理连接状态变化失败: {e}", exc_info=True)
|
||||
|
||||
def _power_on_experiment_table(self) -> None:
|
||||
"""实验台上电按钮点击事件"""
|
||||
try:
|
||||
# 确认对话框
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"确认上电",
|
||||
"确定要给实验台上电吗?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
)
|
||||
|
||||
if reply != QMessageBox.Yes:
|
||||
return
|
||||
|
||||
self.logger.info("[实验台上电] 开始执行上电操作")
|
||||
self.statusBar().showMessage("正在执行实验台上电...", 2000)
|
||||
|
||||
# 写入 Modbus 寄存器:0x5555 = 上电(合闸)
|
||||
# 参考 pcm-influxdb-debug.py:0x5555 会触发 closeBreaker()(合闸/上电)
|
||||
success = self._write_modbus_control_register(0x5555)
|
||||
|
||||
if success:
|
||||
self.logger.info("[实验台上电] ✅ 上电指令发送成功")
|
||||
self.statusBar().showMessage("✅ 实验台上电成功", 3000)
|
||||
else:
|
||||
self.logger.error("[实验台上电] ❌ 上电指令发送失败")
|
||||
self.statusBar().showMessage("❌ 实验台上电失败,请检查Modbus连接", 5000)
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"上电失败",
|
||||
"实验台上电失败,请检查:\n"
|
||||
"1. Modbus连接配置是否正确\n"
|
||||
"2. 设备是否在线\n"
|
||||
"3. 指令值是否正确"
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.error(f"[实验台上电] 异常: {e}", exc_info=True)
|
||||
self.statusBar().showMessage(f"❌ 实验台上电异常: {e}", 5000)
|
||||
QMessageBox.critical(self, "错误", f"实验台上电时发生异常: {str(e)}")
|
||||
|
||||
def _power_off_experiment_table(self) -> None:
|
||||
"""实验台断电按钮点击事件"""
|
||||
try:
|
||||
# 确认对话框
|
||||
reply = QMessageBox.question(
|
||||
self,
|
||||
"确认断电",
|
||||
"确定要给实验台断电吗?",
|
||||
QMessageBox.Yes | QMessageBox.No,
|
||||
QMessageBox.No
|
||||
)
|
||||
|
||||
if reply != QMessageBox.Yes:
|
||||
return
|
||||
|
||||
self.logger.info("[实验台断电] 开始执行断电操作")
|
||||
self.statusBar().showMessage("正在执行实验台断电...", 2000)
|
||||
|
||||
# 写入 Modbus 寄存器:0x0000 = 断电(开闸)
|
||||
# 参考 pcm-influxdb-debug.py:0x0000 会触发 openBreaker()(开闸/断电)
|
||||
success = self._write_modbus_control_register(0x0000)
|
||||
|
||||
if success:
|
||||
self.logger.info("[实验台断电] ✅ 断电指令发送成功")
|
||||
self.statusBar().showMessage("✅ 实验台断电成功", 3000)
|
||||
else:
|
||||
self.logger.error("[实验台断电] ❌ 断电指令发送失败")
|
||||
self.statusBar().showMessage("❌ 实验台断电失败,请检查Modbus连接", 5000)
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"断电失败",
|
||||
"实验台断电失败,请检查:\n"
|
||||
"1. Modbus连接配置是否正确\n"
|
||||
"2. 设备是否在线\n"
|
||||
"3. 指令值是否正确"
|
||||
)
|
||||
except Exception as e:
|
||||
self.logger.error(f"[实验台断电] 异常: {e}", exc_info=True)
|
||||
self.statusBar().showMessage(f"❌ 实验台断电异常: {e}", 5000)
|
||||
QMessageBox.critical(self, "错误", f"实验台断电时发生异常: {str(e)}")
|
||||
|
||||
def _write_modbus_control_register(self, value: int) -> bool:
|
||||
"""通过原始Socket直接发送Modbus TCP报文写入控制寄存器1200
|
||||
完全抛弃pymodbus,使用最底层的socket通信,模拟Modbus Poll的行为
|
||||
|
||||
Args:
|
||||
value: 控制值 (0x5555=继续/开始, 0xAAAA=暂停, 0xFFFF=作废, 1=开始记录, 0=停止记录)
|
||||
value: 控制值 (0x5555=继续/开始/上电合闸, 0xAAAA=暂停, 0xFFFF=作废, 0x0000=停止/断电开闸, 1=开始记录, 0=停止记录)
|
||||
|
||||
Returns:
|
||||
bool: 写入是否成功
|
||||
|
|
@ -6124,6 +6251,74 @@ class MainWindow(QMainWindow):
|
|||
return ts
|
||||
|
||||
|
||||
def _cleanup_incomplete_experiments_on_startup() -> None:
|
||||
"""
|
||||
应用启动时清理上次异常退出遗留的实验记录:
|
||||
- 对于已经开始(start_ts 不为空)、但没有结束时间(end_ts 为空)、且未标记作废(is_terminated=0)的记录,
|
||||
自动标记为作废,并补充 end_ts 和 remark。
|
||||
"""
|
||||
try:
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
from logger import get_logger
|
||||
|
||||
logger = get_logger()
|
||||
db_path = Path(__file__).parent / "experiments.db"
|
||||
|
||||
if not db_path.exists():
|
||||
return
|
||||
|
||||
db = sqlite3.connect(str(db_path))
|
||||
cur = db.cursor()
|
||||
|
||||
# 查找未正常结束且未标记作废的实验
|
||||
cur.execute(
|
||||
"""
|
||||
SELECT id, start_ts, end_ts, is_terminated, remark
|
||||
FROM experiments
|
||||
WHERE start_ts IS NOT NULL
|
||||
AND (end_ts IS NULL OR end_ts = '')
|
||||
AND (is_terminated IS NULL OR is_terminated = 0)
|
||||
"""
|
||||
)
|
||||
rows = cur.fetchall()
|
||||
|
||||
if not rows:
|
||||
db.close()
|
||||
return
|
||||
|
||||
logger.info("[启动清理] 检测到 %d 条未正常结束的实验记录,将标记为作废", len(rows))
|
||||
|
||||
for eid, start_ts, end_ts, is_terminated, remark in rows:
|
||||
cur.execute(
|
||||
"""
|
||||
UPDATE experiments
|
||||
SET
|
||||
end_ts = COALESCE(end_ts, datetime('now')),
|
||||
is_terminated = 1,
|
||||
remark = CASE
|
||||
WHEN remark IS NULL OR remark = '' THEN '作废-程序异常退出'
|
||||
WHEN remark LIKE '%作废-程序异常退出%' THEN remark
|
||||
ELSE remark || ' [作废-程序异常退出]'
|
||||
END
|
||||
WHERE id = ?
|
||||
""",
|
||||
(eid,),
|
||||
)
|
||||
logger.info("[启动清理] 实验 %s 已标记为作废(程序异常退出)", eid)
|
||||
|
||||
db.commit()
|
||||
db.close()
|
||||
|
||||
except Exception as e:
|
||||
try:
|
||||
from logger import get_logger
|
||||
logger = get_logger()
|
||||
logger.error("[启动清理] 清理未完成实验记录失败: %s", e, exc_info=True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
def run_app() -> None:
|
||||
import sys
|
||||
|
||||
|
|
@ -6174,6 +6369,9 @@ def run_app() -> None:
|
|||
logger = get_logger()
|
||||
logger.error("数据库初始化失败,程序可能无法正常运行")
|
||||
# 继续运行,但记录错误
|
||||
else:
|
||||
# 数据库结构准备好后,清理上次异常退出遗留的实验记录
|
||||
_cleanup_incomplete_experiments_on_startup()
|
||||
except Exception as e:
|
||||
logger = get_logger()
|
||||
logger.error(f"数据库初始化异常: {e}", exc_info=True)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
|||
字典包含:
|
||||
- work_order_no: 工单号
|
||||
- process_no: 工序号 (CSYMBOL)
|
||||
- process_name: 工序名称 (CNEXTPROCNAME)
|
||||
- process_name: 工序名称 (CPROCNAME)
|
||||
- part_no: 零件号 (CMATERIALSYMBOL)
|
||||
- executor: 执行人 (CEXCUTOR)
|
||||
"""
|
||||
|
|
@ -169,13 +169,13 @@ def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
|||
sql_query = """
|
||||
SELECT
|
||||
mte.CSYMBOL,
|
||||
mte.CNEXTPROCNAME,
|
||||
mte.CPROCNAME,
|
||||
mpe.CMATERIALSYMBOL,
|
||||
mte.CEXCUTOR
|
||||
FROM MES_TASK_EXTEND mte
|
||||
INNER JOIN MBP_PROJECT_EXTEND mpe ON mte.CPGDID = mpe.CID
|
||||
WHERE mte.CSYMBOL LIKE ?
|
||||
AND RTRIM(LTRIM(ISNULL(mte.CNEXTPROCNAME, ''))) LIKE ?
|
||||
AND RTRIM(LTRIM(ISNULL(mte.CPROCNAME, ''))) LIKE ?
|
||||
"""
|
||||
|
||||
# 添加通配符进行模糊匹配
|
||||
|
|
@ -193,7 +193,7 @@ def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
|||
work_order_info = {
|
||||
'work_order_no': work_order_no,
|
||||
'process_no': row.CSYMBOL if row.CSYMBOL else '', # 工序号
|
||||
'process_name': row.CNEXTPROCNAME if row.CNEXTPROCNAME else '', # 工序名称
|
||||
'process_name': row.CPROCNAME if row.CPROCNAME else '', # 工序名称
|
||||
'part_no': row.CMATERIALSYMBOL if row.CMATERIALSYMBOL else '', # 零件号
|
||||
'executor': row.CEXCUTOR if row.CEXCUTOR else '' # 执行人
|
||||
}
|
||||
|
|
@ -226,13 +226,13 @@ def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
|||
sql_query = """
|
||||
SELECT
|
||||
mte.CSYMBOL,
|
||||
mte.CNEXTPROCNAME,
|
||||
mte.CPROCNAME,
|
||||
mpe.CMATERIALSYMBOL,
|
||||
mte.CEXCUTOR
|
||||
FROM MES_TASK_EXTEND mte
|
||||
INNER JOIN MBP_PROJECT_EXTEND mpe ON mte.CPGDID = mpe.CID
|
||||
WHERE mte.CSYMBOL LIKE %s
|
||||
AND RTRIM(LTRIM(ISNULL(mte.CNEXTPROCNAME, ''))) LIKE %s
|
||||
AND RTRIM(LTRIM(ISNULL(mte.CPROCNAME, ''))) LIKE %s
|
||||
"""
|
||||
|
||||
# 添加通配符进行模糊匹配
|
||||
|
|
@ -249,7 +249,7 @@ def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
|||
work_order_info = {
|
||||
'work_order_no': work_order_no,
|
||||
'process_no': result.get('CSYMBOL', ''),
|
||||
'process_name': result.get('CNEXTPROCNAME', ''),
|
||||
'process_name': result.get('CPROCNAME', ''),
|
||||
'part_no': result.get('CMATERIALSYMBOL', ''),
|
||||
'executor': result.get('CEXCUTOR', '')
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue