302 lines
11 KiB
Python
302 lines
11 KiB
Python
#!/usr/bin/env python
|
||
# -*- coding: utf-8 -*-
|
||
"""
|
||
工单查询模块 - 独立的SQL Server查询功能
|
||
"""
|
||
import json
|
||
import os
|
||
from typing import Dict, Optional
|
||
from pathlib import Path
|
||
from logger import get_logger
|
||
|
||
logger = get_logger()
|
||
|
||
# 配置文件路径
|
||
CONFIG_FILE = Path(__file__).parent / 'work_order_db_config.json'
|
||
|
||
# 默认配置
|
||
DEFAULT_CONFIG = {
|
||
'debug_mode': False, # Debug模式:True时使用假数据,不连接数据库
|
||
'host': 'localhost', # 数据库服务器地址
|
||
'port': 1433, # SQL Server端口(通常是1433)
|
||
'database': 'MES_DB', # 数据库名
|
||
'username': 'sa', # 用户名
|
||
'password': 'password', # 密码
|
||
'charset': 'utf8mb4'
|
||
}
|
||
|
||
|
||
def load_db_config() -> Dict[str, any]:
|
||
"""
|
||
从配置文件加载数据库配置
|
||
如果配置文件不存在,则创建默认配置文件
|
||
"""
|
||
if CONFIG_FILE.exists():
|
||
try:
|
||
with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
|
||
config = json.load(f)
|
||
# 只提取需要的配置项
|
||
return {
|
||
'debug_mode': config.get('debug_mode', DEFAULT_CONFIG['debug_mode']),
|
||
'host': config.get('host', DEFAULT_CONFIG['host']),
|
||
'port': config.get('port', DEFAULT_CONFIG['port']),
|
||
'database': config.get('database', DEFAULT_CONFIG['database']),
|
||
'username': config.get('username', DEFAULT_CONFIG['username']),
|
||
'password': config.get('password', DEFAULT_CONFIG['password']),
|
||
'charset': config.get('charset', DEFAULT_CONFIG['charset'])
|
||
}
|
||
except Exception as e:
|
||
logger.error(f"读取配置文件失败: {e}")
|
||
return DEFAULT_CONFIG.copy()
|
||
else:
|
||
# 创建默认配置文件
|
||
try:
|
||
with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
|
||
config_with_desc = DEFAULT_CONFIG.copy()
|
||
config_with_desc['description'] = '工单数据库连接配置'
|
||
config_with_desc['comment'] = '请根据实际环境修改以上配置'
|
||
json.dump(config_with_desc, f, ensure_ascii=False, indent=2)
|
||
logger.info(f"已创建默认配置文件: {CONFIG_FILE}")
|
||
except Exception as e:
|
||
logger.error(f"创建配置文件失败: {e}")
|
||
return DEFAULT_CONFIG.copy()
|
||
|
||
|
||
# 工单数据库配置(从文件加载)
|
||
WORK_ORDER_DB_CONFIG = load_db_config()
|
||
|
||
|
||
def reload_config():
|
||
"""
|
||
重新加载配置文件
|
||
"""
|
||
global WORK_ORDER_DB_CONFIG
|
||
WORK_ORDER_DB_CONFIG = load_db_config()
|
||
logger.info("工单数据库配置已重新加载")
|
||
|
||
|
||
def query_work_order(work_order_no: str) -> Optional[Dict[str, str]]:
|
||
"""
|
||
查询工单信息 - SQL Server版本
|
||
|
||
Args:
|
||
work_order_no: 工单号
|
||
|
||
Returns:
|
||
包含工单信息的字典,如果查询失败则返回None
|
||
字典包含:
|
||
- work_order_no: 工单号
|
||
- process_no: 工序号 (CSYMBOL)
|
||
- part_no: 零件号 (CMATERIALSYMBOL)
|
||
- executor: 执行人 (CEXCUTOR)
|
||
"""
|
||
if not work_order_no:
|
||
logger.warning("工单号为空")
|
||
return None
|
||
|
||
# Debug模式:返回假数据
|
||
if WORK_ORDER_DB_CONFIG.get('debug_mode', False):
|
||
logger.info(f"[DEBUG模式] 返回工单号 {work_order_no} 的假数据")
|
||
return {
|
||
'work_order_no': work_order_no,
|
||
'process_no': 'DEBUG-001',
|
||
'part_no': 'PART-DEBUG-12345',
|
||
'executor': '测试人员'
|
||
}
|
||
|
||
conn = None
|
||
cursor = None
|
||
try:
|
||
import pyodbc
|
||
|
||
# 尝试不同的ODBC驱动
|
||
drivers = [
|
||
"ODBC Driver 17 for SQL Server",
|
||
"ODBC Driver 18 for SQL Server",
|
||
"ODBC Driver 13 for SQL Server",
|
||
"ODBC Driver 11 for SQL Server",
|
||
"SQL Server Native Client 11.0",
|
||
"SQL Server Native Client 10.0",
|
||
"SQL Server"
|
||
]
|
||
|
||
# 查找可用的驱动
|
||
available_drivers = pyodbc.drivers()
|
||
driver_to_use = None
|
||
|
||
for driver in drivers:
|
||
if driver in available_drivers:
|
||
driver_to_use = driver
|
||
logger.info(f"使用ODBC驱动: {driver}")
|
||
break
|
||
|
||
if not driver_to_use:
|
||
logger.warning(f"未找到合适的SQL Server ODBC驱动,可用驱动: {available_drivers}")
|
||
# 尝试使用第一个包含SQL的驱动
|
||
for available in available_drivers:
|
||
if 'SQL' in available.upper():
|
||
driver_to_use = available
|
||
logger.info(f"尝试使用驱动: {driver_to_use}")
|
||
break
|
||
|
||
if not driver_to_use:
|
||
raise Exception("未找到SQL Server ODBC驱动,将尝试pymssql")
|
||
|
||
# 构建SQL Server连接字符串
|
||
conn_str = (
|
||
f"DRIVER={{{driver_to_use}}};"
|
||
f"SERVER={WORK_ORDER_DB_CONFIG['host']},{WORK_ORDER_DB_CONFIG['port']};"
|
||
f"DATABASE={WORK_ORDER_DB_CONFIG['database']};"
|
||
f"UID={WORK_ORDER_DB_CONFIG['username']};"
|
||
f"PWD={WORK_ORDER_DB_CONFIG['password']}"
|
||
)
|
||
|
||
logger.info(f"连接到SQL Server: {WORK_ORDER_DB_CONFIG['host']}:{WORK_ORDER_DB_CONFIG['port']}/{WORK_ORDER_DB_CONFIG['database']}")
|
||
|
||
# 连接数据库
|
||
conn = pyodbc.connect(conn_str)
|
||
cursor = conn.cursor()
|
||
|
||
# 构建SQL查询语句(SQL Server使用?作为参数占位符)
|
||
# 使用LIKE模糊匹配,支持工单号前缀查询(如 W2001150.001 可以匹配 W2001150.001-01:10)
|
||
sql_query = """
|
||
SELECT
|
||
mte.CSYMBOL,
|
||
mpe.CMATERIALSYMBOL,
|
||
mte.CEXCUTOR
|
||
FROM MES_TASK_EXTEND mte
|
||
INNER JOIN MBP_PROJECT_EXTEND mpe ON mte.CPGDID = mpe.CID
|
||
WHERE mte.CSYMBOL LIKE ?
|
||
"""
|
||
|
||
# 添加通配符进行模糊匹配
|
||
search_pattern = f"{work_order_no}%"
|
||
logger.debug(f"执行查询: {sql_query} with parameter: {search_pattern}")
|
||
cursor.execute(sql_query, search_pattern)
|
||
row = cursor.fetchone()
|
||
|
||
if not row:
|
||
logger.warning(f"未找到工单号 '{work_order_no}' 的相关信息")
|
||
return None
|
||
|
||
# 提取查询结果 - pyodbc返回Row对象,可以通过索引或属性访问
|
||
work_order_info = {
|
||
'work_order_no': work_order_no,
|
||
'process_no': row.CSYMBOL if row.CSYMBOL else '', # 工序号
|
||
'part_no': row.CMATERIALSYMBOL if row.CMATERIALSYMBOL else '', # 零件号
|
||
'executor': row.CEXCUTOR if row.CEXCUTOR else '' # 执行人
|
||
}
|
||
|
||
logger.info(f"工单查询成功: {work_order_info}")
|
||
return work_order_info
|
||
|
||
except ImportError:
|
||
logger.error("pyodbc未安装,请运行: pip install pyodbc")
|
||
|
||
# 尝试使用pymssql作为备选
|
||
try:
|
||
import pymssql
|
||
logger.info("尝试使用pymssql连接SQL Server")
|
||
|
||
conn = pymssql.connect(
|
||
server=WORK_ORDER_DB_CONFIG['host'],
|
||
port=WORK_ORDER_DB_CONFIG['port'],
|
||
user=WORK_ORDER_DB_CONFIG['username'],
|
||
password=WORK_ORDER_DB_CONFIG['password'],
|
||
database=WORK_ORDER_DB_CONFIG['database']
|
||
)
|
||
|
||
cursor = conn.cursor(as_dict=True)
|
||
|
||
# 使用LIKE模糊匹配,支持工单号前缀查询
|
||
sql_query = """
|
||
SELECT
|
||
mte.CSYMBOL,
|
||
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
|
||
"""
|
||
|
||
search_pattern = f"{work_order_no}%"
|
||
cursor.execute(sql_query, search_pattern)
|
||
result = cursor.fetchone()
|
||
|
||
if not result:
|
||
logger.warning(f"未找到工单号 '{work_order_no}' 的相关信息")
|
||
return None
|
||
|
||
work_order_info = {
|
||
'work_order_no': work_order_no,
|
||
'process_no': result.get('CSYMBOL', ''),
|
||
'part_no': result.get('CMATERIALSYMBOL', ''),
|
||
'executor': result.get('CEXCUTOR', '')
|
||
}
|
||
|
||
logger.info(f"工单查询成功(pymssql): {work_order_info}")
|
||
return work_order_info
|
||
|
||
except ImportError:
|
||
error_msg = "SQL Server驱动未安装,请安装以下任一库:\n1. pip install pyodbc\n2. pip install pymssql"
|
||
logger.error(error_msg)
|
||
raise Exception(error_msg)
|
||
except Exception as e:
|
||
logger.error(f"pymssql查询错误: {e}")
|
||
raise Exception(f"数据库查询错误: {e}")
|
||
|
||
except Exception as e:
|
||
logger.error(f"SQL Server查询错误: {e}")
|
||
raise Exception(f"数据库查询错误: {e}")
|
||
finally:
|
||
if cursor:
|
||
cursor.close()
|
||
if conn:
|
||
conn.close()
|
||
logger.debug("数据库连接已关闭")
|
||
|
||
|
||
def update_work_order_db_config(host: str = None, port: int = None,
|
||
database: str = None, username: str = None,
|
||
password: str = None, save_to_file: bool = True):
|
||
"""
|
||
更新工单数据库连接配置
|
||
|
||
Args:
|
||
host: 数据库服务器地址
|
||
port: 数据库端口
|
||
database: 数据库名
|
||
username: 用户名
|
||
password: 密码
|
||
save_to_file: 是否保存到配置文件
|
||
"""
|
||
global WORK_ORDER_DB_CONFIG
|
||
|
||
if host is not None:
|
||
WORK_ORDER_DB_CONFIG['host'] = host
|
||
if port is not None:
|
||
WORK_ORDER_DB_CONFIG['port'] = port
|
||
if database is not None:
|
||
WORK_ORDER_DB_CONFIG['database'] = database
|
||
if username is not None:
|
||
WORK_ORDER_DB_CONFIG['username'] = username
|
||
if password is not None:
|
||
WORK_ORDER_DB_CONFIG['password'] = password
|
||
|
||
logger.info(f"工单数据库配置已更新: host={WORK_ORDER_DB_CONFIG['host']}, "
|
||
f"port={WORK_ORDER_DB_CONFIG['port']}, database={WORK_ORDER_DB_CONFIG['database']}")
|
||
|
||
# 保存到配置文件
|
||
if save_to_file:
|
||
try:
|
||
config_to_save = WORK_ORDER_DB_CONFIG.copy()
|
||
config_to_save['description'] = '工单数据库连接配置'
|
||
config_to_save['comment'] = '请根据实际环境修改以上配置'
|
||
|
||
with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
|
||
json.dump(config_to_save, f, ensure_ascii=False, indent=2)
|
||
logger.info(f"配置已保存到文件: {CONFIG_FILE}")
|
||
except Exception as e:
|
||
logger.error(f"保存配置文件失败: {e}")
|
||
|