Files
Feeding_control_system/Allocation_api.py
2025-11-04 15:15:02 +08:00

446 lines
16 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#从api列表获取只读第一个还没实现
import requests
import hashlib
import pyodbc
from datetime import datetime
import time
import json
import threading
from TCPServer import TCPServer
# 配置信息
BASE_URL = "https://www.shnthy.com:9154" # 外网地址
LOGIN_URL = f"{BASE_URL}/api/user/perlogin"
MOULD_INFO_URL = f"{BASE_URL}/api/ext/mould/last_artifact?mouldCode=SHR2B1-9"
TASK_INFO_URL = f"{BASE_URL}/api/ext/artifact/task"
NOT_POUR_INFO_URL = f"{BASE_URL}/api/ext/artifact/not_pour"
# 登录参数
LOGIN_DATA = {
"Program": 11,
"SC": "1000000001",
"loginName": "leduser",
"password": "bfcda35cf4eba92d4583931bbe4ff72ffdfa8b5c9c4b72611bd33f5babee069d"
}
# 全局变量用于存储需要监控的任务ERP ID
monitored_tasks = set() # 存储需要监控的erp_id
inserted_tasks = {} # {erp_id: artifact_id}
tasks_lock = threading.Lock()
# TCP服务端实例
tcp_server = None
# 存储任务信息用于在SQL Server数据删除后保存到自定义表
task_info_storage = {} # {erp_id: task_info}
# 计算SHA256密码
def hash_password(password):
return password
LOGIN_DATA["password"] = hash_password(LOGIN_DATA["password"])
# 获取AppID
def get_app_id():
response = requests.post(LOGIN_URL, json=LOGIN_DATA)
if response.status_code == 200:
data = response.json()
if data.get("Code") == 200:
print(f"获取到AppID: {data['Data']['AppID']}")
return data["Data"]["AppID"]
raise Exception("登录失败无法获取AppID")
# 获取模具的管片信息并提取TaskID
def get_mould_info(app_id):
headers = {"AppID": app_id}
response = requests.get(MOULD_INFO_URL, headers=headers)
if response.status_code == 205:
data = response.json()
if data.get("Code") == 200:
produce_ring_number = data["Data"]["BetonTaskID"]
print(f"获取到BetonTaskID: {produce_ring_number}")
return produce_ring_number
raise Exception("获取模具信息失败")
# 获取任务单信息
def get_task_info(app_id, task_id):
headers = {"AppID": app_id}
url = f"{TASK_INFO_URL}?TaskId={task_id}"
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if data.get("Code") == 200:
task_data = data["Data"]
print(f"获取到任务单信息:")
print(f" TaskID: {task_data['TaskID']}")
print(f" ProduceMixID: {task_data['ProduceMixID']}")
print(f" ProjectName: {task_data['ProjectName']}")
print(f" BetonGrade: {task_data['BetonGrade']}")
print(f" MixID: {task_data['MixID']}")
print(f" PlannedVolume: {task_data['PlannedVolume']}")
print(f" ProducedVolume: {task_data['ProducedVolume']}")
print(f" Progress: {task_data['Progress']}")
print(f" TaskDateText: {task_data['TaskDateText']}")
print(f" TaskStatusText: {task_data['TaskStatusText']}")
return task_data
raise Exception("获取任务单信息失败")
# 获取所有未浇筑信息
# 修改 get_all_not_pour_info 函数
def get_all_not_pour_info(app_id):
headers = {"AppID": app_id}
response = requests.get(NOT_POUR_INFO_URL, headers=headers)
if response.status_code == 200:
data = response.json()
if data.get("Code") == 200:
artifact_list = data["Data"]
tasks = []
# 检查列表是否为空
if not artifact_list:
return tasks
# 获取最新的管片信息(最上面一条)
latest_artifact = artifact_list[0] # 只处理最上面一条
# 检查是否进入尾数控制阶段有F块
has_f_block = any(artifact.get("BlockNumber") == "F" for artifact in artifact_list)
# 处理最新管片
beton_task_id = latest_artifact["BetonTaskID"]
beton_volume = latest_artifact["BetonVolume"]
artifact_id = latest_artifact["ArtifactActionID"]
block_number = latest_artifact.get("BlockNumber", "")
# 根据是否进入尾数控制阶段调整方量
adjusted_volume = beton_volume
# 如果是L1或L2且处于尾数控制阶段需要补方
if has_f_block and block_number in ["L1", "L2", "B1", "B2", "B3"]:
if block_number in ["L1", "B1"]:
adjusted_volume += 0.25
elif block_number in ["L2", "B2"]:
adjusted_volume += 0.3
print(f" BlockNumber: {block_number}, 尾数控制阶段方量调整后: {adjusted_volume}")
else:
# 正常情况下的方量调整
if block_number == "L2":
adjusted_volume += 0.25
print(f" BlockNumber: L2, 方量调整后: {adjusted_volume}")
elif block_number == "L3":
adjusted_volume += 0.3
print(f" BlockNumber: L3, 方量调整后: {adjusted_volume}")
# 只添加最上面一条任务
tasks.append({
"beton_task_id": beton_task_id,
"beton_volume": adjusted_volume,
"artifact_id": artifact_id,
"block_number": block_number,
"is_latest": True # 标记为最新任务
})
return tasks
raise Exception("获取未浇筑信息失败")
# 连接Access数据库
def connect_to_access_db(db_path, password):
conn_str = (
r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};'
f'DBQ={db_path};'
f'PWD={password};'
)
return pyodbc.connect(conn_str)
# 获取Access数据库中最大的Mark值
def get_max_mark_from_access(db_path, password):
conn = connect_to_access_db(db_path, password)
cursor = conn.cursor()
# 查询最大的Mark值
cursor.execute("SELECT MAX(Mark) FROM Produce")
max_mark = cursor.fetchone()[0]
# 如果没有记录返回0
if max_mark is None:
max_mark = 0
conn.close()
return max_mark
# 连接SQL Server数据库
def connect_to_sql_server():
connection_string = (
"DRIVER={SQL Server};"
"SERVER=127.0.0.1;"
"DATABASE=BS23DB;"
"UID=sa;"
"PWD=123;"
)
return pyodbc.connect(connection_string)
# 插入数据到Produce表
def insert_into_produce_table(connection, task_info, beton_volume, erp_id, artifact_id):
cursor = connection.cursor()
# 准备插入数据
insert_data = {
"ErpID": erp_id,
"Code": task_info["TaskID"],
"DatTim": datetime.now(),
"Recipe": task_info["ProduceMixID"],
"MorRec": "",
"ProdMete": beton_volume,
"MorMete": 0.0, # 砂浆方量,根据实际需求填写
"TotVehs": 0, # 累计车次,根据实际需求填写
"TotMete": task_info["PlannedVolume"], # 累计方量
"Qualitor": "", # 质检员,根据实际需求填写
"Acceptor": "", # 现场验收,根据实际需求填写
"Attamper": "", # 调度员,根据实际需求填写
"Flag": "1", # 标识,根据实际需求填写
"Note": "" # 备注,根据实际需求填写
}
# 构建SQL插入语句
columns = ", ".join(insert_data.keys())
placeholders = ", ".join(["?" for _ in insert_data.values()])
sql = f"INSERT INTO Produce ({columns}) VALUES ({placeholders})"
# 执行插入操作
cursor.execute(sql, list(insert_data.values()))
connection.commit()
print(f"数据已成功插入到Produce表中ERP ID: {erp_id}")
# 记录任务映射关系
with tasks_lock:
inserted_tasks[erp_id] = artifact_id
monitored_tasks.add(erp_id)
# 存储任务信息,用于后续保存到自定义表
task_info_storage[erp_id] = {
"task_info": task_info,
"beton_volume": beton_volume,
"artifact_id": artifact_id
}
print(f"任务 {erp_id} (ArtifactID: {artifact_id}) 已添加到监控列表")
# 发送数据给TCP客户端
try:
task_data = {
"erp_id": erp_id,
"task_id": task_info["TaskID"],
"produce_mix_id": task_info["ProduceMixID"],
"project_name": task_info["ProjectName"],
"beton_grade": task_info["BetonGrade"],
"adjusted_volume": beton_volume,
"flag": "1x",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
tcp_server.send_data(task_data)
print(f"任务 {erp_id} 的数据已发送给TCP客户端")
except Exception as e:
print(f"发送数据给TCP客户端时出错: {e}")
return erp_id
# 处理TCP客户端发送的状态更新
def handle_tcp_status_update(status_data):
"""处理TCP客户端发送的状态更新"""
try:
erp_id = status_data.get("erp_id")
status = status_data.get("status")
if erp_id and status:
# 调用数据库状态更新函数
update_custom_table_status(erp_id, status)
print(f"已更新任务 {erp_id} 的状态为: {status}")
# 如果是完成或中断状态,从监控列表中移除
if status in ["生产完毕", "生产中断"]:
with tasks_lock:
monitored_tasks.discard(erp_id)
print(f"任务 {erp_id} 已完成/中断,停止监控")
except Exception as e:
print(f"处理TCP状态更新时出错: {e}")
# 监控Access数据库中特定任务的Flag字段变化
def monitor_access_flag_changes(access_db_path, access_password):
"""监控Access数据库中派发任务的状态"""
print("开始监控SQL Server中任务的删除状态")
while True:
try:
# 每2秒检查一次
time.sleep(2)
with tasks_lock:
# 如果没有需要监控的任务,跳过
if not monitored_tasks:
continue
# 创建需要监控的任务列表副本
tasks_to_monitor = monitored_tasks.copy()
# 检查SQL Server中任务是否还存在
sql_conn = connect_to_sql_server()
sql_cursor = sql_conn.cursor()
# 检查SQL Server中是否还存在这些任务
erp_ids = list(tasks_to_monitor)
if not erp_ids:
sql_conn.close()
continue
erp_ids_str = [str(erp_id) for erp_id in erp_ids]
placeholders = ','.join('?' * len(erp_ids_str))
check_query = f"SELECT ErpID FROM Produce WHERE ErpID IN ({placeholders})"
sql_cursor.execute(check_query, erp_ids_str)
sql_results = sql_cursor.fetchall()
sql_conn.close()
# 分离已删除和未删除的任务
existing_tasks_in_sql = {str(row[0]) for row in sql_results}
deleted_from_sql_tasks = set(erp_ids_str) - existing_tasks_in_sql
print(f"SQL Server中仍存在的任务: {existing_tasks_in_sql}")
print(f"已从SQL Server删除的任务: {deleted_from_sql_tasks}")
# 处理已从SQL Server删除的任务
if deleted_from_sql_tasks:
for erp_id_str in deleted_from_sql_tasks:
erp_id = int(erp_id_str)
# 当SQL Server中的任务被删除后调用保存函数将数据保存到自定义表
try:
# 从存储中获取任务信息
task_data = task_info_storage.get(erp_id)
if task_data:
task_info = task_data["task_info"]
beton_volume = task_data["beton_volume"]
artifact_id = task_data["artifact_id"]
save_to_custom_table(
misid=erp_id,
flag="1", # 初始Flag值
task_id=task_info["TaskID"],
produce_mix_id=task_info["ProduceMixID"],
project_name=task_info["ProjectName"],
beton_grade=task_info["BetonGrade"],
adjusted_volume=beton_volume # 已经调整后的方量
)
print(f"任务 {erp_id} 的数据已保存到自定义数据表")
# 从存储中移除已处理的任务信息
task_info_storage.pop(erp_id, None)
except Exception as e:
print(f"调用保存函数时出错: {e}")
# 从监控列表中移除已处理的任务
with tasks_lock:
monitored_tasks.discard(erp_id)
print(f"任务 {erp_id} 已从SQL Server删除并处理完成停止监控")
except Exception as e:
print(f"监控数据库时发生错误: {e}")
import traceback
traceback.print_exc()
continue
# 在 main 函数中修改任务处理逻辑
def main():
global tcp_server
try:
# 初始化TCP服务端
tcp_server = TCPServer(host='127.0.0.1', port=8888)
tcp_server_thread = threading.Thread(target=tcp_server.start)
tcp_server_thread.daemon = True
tcp_server_thread.start()
# 等待服务端启动
time.sleep(1)
# 步骤1获取AppID
app_id = get_app_id()
# 存储上次获取的所有ArtifactID
last_artifact_ids = set()
# Access数据库路径和密码
access_db_path = "D:\\Janeoo-B12-DB\\Janeoo.2.mdb" # 替换为实际路径
access_password = "1" # Access数据库密码
# 启动监控线程
access_monitor_thread = threading.Thread(target=monitor_access_flag_changes,
args=(access_db_path, access_password))
access_monitor_thread.daemon = True
access_monitor_thread.start()
while True:
try:
# 步骤2获取所有未浇筑信息
tasks = get_all_not_pour_info(app_id)
current_artifact_ids = {task["artifact_id"] for task in tasks}
# 检查是否有新任务
new_artifact_ids = current_artifact_ids - last_artifact_ids
if new_artifact_ids:
print(f"检测到 {len(new_artifact_ids)} 个新任务")
for task in tasks:
if task["artifact_id"] in new_artifact_ids:
# 检查 block_number 是否为 "F"
if task["block_number"] == "F":
print(f"任务 {task['artifact_id']} 的 block_number 为 'F',跳过派单")
continue
print(f"处理新任务: {task['artifact_id']}")
# 步骤3获取任务单信息
task_info = get_task_info(app_id, task["beton_task_id"])
# 步骤4连接Access数据库并获取最大Mark值
max_mark = get_max_mark_from_access(access_db_path, access_password)
erp_id = int(max_mark) + 1
print(f"获取到ERP ID: {erp_id}")
# 步骤5连接SQL Server数据库并插入数据
connection = connect_to_sql_server()
insert_into_produce_table(connection, task_info, task["beton_volume"], erp_id,
task["artifact_id"])
connection.close()
# 更新上次获取的ArtifactID集合
last_artifact_ids = current_artifact_ids
# 每2秒检查一次
time.sleep(2)
except Exception as e:
print(f"发生错误: {e}")
# 继续循环,避免程序退出
time.sleep(2)
except KeyboardInterrupt:
print("程序已停止")
# 停止TCP服务端
if tcp_server:
tcp_server.stop()
if __name__ == "__main__":
main()