diff --git a/.idea/InsertData.iml b/.idea/InsertData.iml index 34a5697..29bca85 100644 --- a/.idea/InsertData.iml +++ b/.idea/InsertData.iml @@ -4,7 +4,7 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index df3bfff..db5199f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,5 +3,5 @@ - + \ No newline at end of file diff --git a/API/__init__.py b/API/__init__.py new file mode 100644 index 0000000..d6f9a40 --- /dev/null +++ b/API/__init__.py @@ -0,0 +1,5 @@ +"""API包""" +from .client import APIClient +from .mix_weight_api import MixWeightAPI + +__all__ = ['APIClient', 'MixWeightAPI'] diff --git a/API/__pycache__/__init__.cpython-39.pyc b/API/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..28a8f9d Binary files /dev/null and b/API/__pycache__/__init__.cpython-39.pyc differ diff --git a/API/__pycache__/client.cpython-39.pyc b/API/__pycache__/client.cpython-39.pyc new file mode 100644 index 0000000..a6aaaef Binary files /dev/null and b/API/__pycache__/client.cpython-39.pyc differ diff --git a/API/__pycache__/mix_weight_api.cpython-39.pyc b/API/__pycache__/mix_weight_api.cpython-39.pyc new file mode 100644 index 0000000..4f25d7b Binary files /dev/null and b/API/__pycache__/mix_weight_api.cpython-39.pyc differ diff --git a/API/client.py b/API/client.py new file mode 100644 index 0000000..f931a1b --- /dev/null +++ b/API/client.py @@ -0,0 +1,71 @@ +"""API客户端模块""" +import requests +import hashlib +from config.settings import BASE_URL, LOGIN_DATA + + +class APIClient: + def __init__(self): + self.base_url = BASE_URL + self.login_url = f"{BASE_URL}/api/user/perlogin" + self.mould_info_url = f"{BASE_URL}/api/ext/mould/last_artifact?mouldCode=SHR2B1-9" + self.task_info_url = f"{BASE_URL}/api/ext/artifact/task" + self.not_pour_info_url = f"{BASE_URL}/api/ext/artifact/not_pour" + self.app_id = None + + def hash_password(self, password): + """计算SHA256密码""" + return password + + def login(self): + """获取AppID""" + login_data = LOGIN_DATA.copy() + login_data["password"] = self.hash_password(login_data["password"]) + + response = requests.post(self.login_url, json=login_data) + if response.status_code == 200: + data = response.json() + if data.get("Code") == 200: + self.app_id = data["Data"]["AppID"] + return self.app_id + raise Exception("登录失败,无法获取AppID") + + def get_mould_info(self): + """获取模具的管片信息并提取TaskID""" + if not self.app_id: + raise Exception("请先登录获取AppID") + + headers = {"AppID": self.app_id} + response = requests.get(self.mould_info_url, headers=headers) + if response.status_code == 205: + data = response.json() + if data.get("Code") == 200: + return data["Data"]["BetonTaskID"] + raise Exception("获取模具信息失败") + + def get_task_info(self, task_id): + """获取任务单信息""" + if not self.app_id: + raise Exception("请先登录获取AppID") + + headers = {"AppID": self.app_id} + url = f"{self.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: + return data["Data"] + raise Exception("获取任务单信息失败") + + def get_not_pour_info(self): + """获取所有未浇筑信息""" + if not self.app_id: + raise Exception("请先登录获取AppID") + + headers = {"AppID": self.app_id} + response = requests.get(self.not_pour_info_url, headers=headers) + if response.status_code == 200: + data = response.json() + if data.get("Code") == 200: + return data["Data"] + raise Exception("获取未浇筑信息失败") diff --git a/API/mix_weight_api.py b/API/mix_weight_api.py new file mode 100644 index 0000000..269e89a --- /dev/null +++ b/API/mix_weight_api.py @@ -0,0 +1,62 @@ +"""配比重量API模块""" +from flask import Flask, jsonify +from database.sql_server_connection import SQLServerConnection + +class MixWeightAPI: + def __init__(self): + self.app = Flask(__name__) + self.db = SQLServerConnection() + self._register_routes() + + def _register_routes(self): + """注册路由""" + self.app.add_url_rule('/API/mix_weights', 'get_mix_weights', self.get_mix_weights, methods=['GET']) + self.app.add_url_rule('/API/mix_weights/', 'get_mix_weight_by_code', + self.get_mix_weight_by_code, methods=['GET']) + + def get_mix_weights(self): + """ + HTTP接口:获取所有配比号及其对应每方重量 + 返回格式:JSON数组 + """ + try: + mix_info = self.db.get_mix_weight_info() + return jsonify({ + "success": True, + "data": mix_info, + "count": len(mix_info) + }), 200 + except Exception as e: + return jsonify({ + "success": False, + "error": str(e) + }), 500 + + def get_mix_weight_by_code(self, code): + """ + HTTP接口:根据配比号获取其对应每方重量 + 返回格式:JSON对象 + """ + try: + mix_info = self.db.get_mix_weight_info() + for item in mix_info: + if item["Code"] == code: + return jsonify({ + "success": True, + "data": item + }), 200 + + return jsonify({ + "success": False, + "error": f"未找到配比号 {code}" + }), 404 + + except Exception as e: + return jsonify({ + "success": False, + "error": str(e) + }), 500 + + def run(self, host='127.0.0.1', port=5001, debug=True, threaded=True): + """启动Flask服务""" + self.app.run(host=host, port=port, debug=debug, threaded=threaded) diff --git a/API/send_data_test.py b/API/send_data_test.py new file mode 100644 index 0000000..4159774 --- /dev/null +++ b/API/send_data_test.py @@ -0,0 +1,273 @@ + +from flask import Flask, request, jsonify +import json +from datetime import datetime +from datetime import timedelta + +app = Flask(__name__) + + +@app.route('/api/user/perlogin', methods=['POST']) +def login(): + """ + 模拟登录接口 - 获取AppID + """ + try: + # 获取请求参数 + data = request.get_json() + + # 验证必要参数 + if not all(k in data for k in ['Program', 'SC', 'loginName', 'password']): + return jsonify({ + "Code": 400, + "Message": "缺少必要参数", + "Data": None + }), 400 + + # 模拟验证逻辑 + expected_login_name = "leduser" + expected_password = "bfcda35cf4eba92d4583931bbe4ff72ffdfa8b5c9c4b72611bd33f5babee069d" + + if data['loginName'] != expected_login_name or data['password'] != expected_password: + return jsonify({ + "Code": 401, + "Message": "用户名或密码错误", + "Data": None + }), 401 + + # 模拟生成AppID和SignToken + app_id = "e00412005f74144a8654d24f9d4b4e5" + sign_token = "79a5c0da-ebfd-4ce3-832d-36c807cc0398" + expire_time = (datetime.now().replace(microsecond=0) + timedelta(hours=24)).isoformat() + + response_data = { + "Code": 200, + "Message": None, + "Data": { + "AppID": app_id, + "SignToken": sign_token, + "ExpireTime": expire_time, + "ZrJwt": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI3OQ" # 简化JWT + } + } + + return jsonify(response_data), 200 + + except Exception as e: + return jsonify({ + "Code": 500, + "Message": f"服务器内部错误: {str(e)}", + "Data": None + }), 500 + + +@app.route('/api/ext/mould/last_artifact', methods=['GET']) +def get_mould_info(): + """ + 模拟获取模具管片信息接口 + """ + try: + # 获取查询参数 + mould_code = request.args.get('mouldCode') + + if not mould_code: + return jsonify({ + "Code": 400, + "Message": "缺少mouldCode参数", + "Data": None + }), 400 + + # 模拟AppID验证(这里简化处理) + app_id = request.headers.get('AppID') + if not app_id: + return jsonify({ + "Code": 401, + "Message": "缺少AppID认证", + "Data": None + }), 401 + + # 模拟返回数据 + response_data = { + "Code": 200, + "Message": None, + "Data": { + "ArtifactID": "QR1B12000151AD", + "ArtifactActionID": 346482967298117, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": mould_code, + "SkeletonID": "QR1B12000046A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "B1", + "HoleRingMarking": "否", + "GroutingPipeMarking": "是", + "PolypropyleneFiberMarking": "是", + "BetonVolume": 6455.0000, + "BetonTaskID": "20251020-01" + } + } + + return jsonify(response_data), 200 + + except Exception as e: + return jsonify({ + "Code": 500, + "Message": f"服务器内部错误: {str(e)}", + "Data": None + }), 500 + + +@app.route('/api/ext/artifact/task', methods=['GET']) +def get_task_info(): + """ + 模拟获取任务单信息接口 + """ + try: + # 获取查询参数 + task_id = request.args.get('TaskId') + + if not task_id: + return jsonify({ + "Code": 400, + "Message": "缺少TaskId参数", + "Data": None + }), 400 + + # 模拟AppID验证 + app_id = request.headers.get('AppID') + if not app_id: + return jsonify({ + "Code": 401, + "Message": "缺少AppID认证", + "Data": None + }), 401 + + # 模拟返回数据 + response_data = { + "Code": 200, + "Message": None, + "Data": { + "TaskID": task_id, + "TaskStatus": 4, + "TaskStatusText": "已制单", + "TaskCount": 600, + "AlreadyProduceCount": 100, + "Progress": "100 / 600", + "ProjectName": "测试新增工程测试", + "TaskPlanDateText": "2025-07-18", + "BetonGrade": "C50", + "MixID": "P20250717001", + "ProduceMixID": "HNT-2025-07-17-001", + "PlannedVolume": 1050.00, + "ProducedVolume": 0.00, + "HoleRingMarking": "咕发环", + "GroutingPipeMarking": "是", + "PolypropyleneFiberMarking": "是", + "TaskDate": "1900-01-01T00:00:00", + "TaskDateText": "1900-01-01", + "PlateCount": 0, + "SendStatus": 0, + "SendStatusText": "未下发", + "MixSendStatus": 0, + "MixSendStatusText": "未下发" + } + } + + return jsonify(response_data), 200 + + except Exception as e: + return jsonify({ + "Code": 500, + "Message": f"服务器内部错误: {str(e)}", + "Data": None + }), 500 + + +@app.route('/api/ext/artifact/not_pour', methods=['GET']) +def get_not_pour_info(): + """ + 模拟获取已入模绑定未浇筑的管片信息接口 + """ + try: + # 模拟AppID验证 + app_id = request.headers.get('AppID') + if not app_id: + return jsonify({ + "Code": 401, + "Message": "缺少AppID认证", + "Data": None + }), 401 + + # 模拟返回多个记录 + response_data = { + "Code": 200, + "Message": None, + "Data": [ + { + "ArtifactID": "QR1B12000151AD", + "ArtifactActionID": 346482967298117, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": "SHR2B1-9", + "SkeletonID": "QR1B12000046A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "B1", + "HoleRingMarking": "否", + "GroutingPipeMarking": "否", + "PolypropyleneFiberMarking": "否", + "BetonVolume": 2.0000, + "BetonTaskID": "20251020-01" + }, + { + "ArtifactID": "QR1B32000153AD", + "ArtifactActionID": 346482967298119, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": "SHR2B3-9", + "SkeletonID": "QR1B2000048A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "B2", + "HoleRingMarking": "否", + "GroutingPipeMarking": "否", + "PolypropyleneFiberMarking": "否", + "BetonVolume": 2.0000, + "BetonTaskID": "20251020-01" + }, + { + "ArtifactID": "QR1B12000151AD", + "ArtifactActionID": 346482967298120, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": "SHR2B1-9", + "SkeletonID": "QR1B12000046A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "B3", + "HoleRingMarking": "否", + "GroutingPipeMarking": "否", + "PolypropyleneFiberMarking": "否", + "BetonVolume": 2.0000, + "BetonTaskID": "20251020-01" + }, + ] + } + + return jsonify(response_data), 200 + + except Exception as e: + return jsonify({ + "Code": 500, + "Message": f"服务器内部错误: {str(e)}", + "Data": None + }), 500 + + +if __name__ == '__main__': + app.run(host='127.0.0.1', port=5000, debug=True) diff --git a/Allocation.py b/Allocation.py deleted file mode 100644 index 5522d6e..0000000 --- a/Allocation.py +++ /dev/null @@ -1,424 +0,0 @@ -#离线版本,根据彭的返回值更新状态,待测试 - -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 = TCPServer - -# 存储任务信息,用于在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("获取任务单信息失败") - - -# 获取所有未浇筑信息 -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 = [] - for artifact in artifact_list: - beton_task_id = artifact["BetonTaskID"] - beton_volume = artifact["BetonVolume"] - artifact_id = artifact["ArtifactActionID"] - block_number = artifact.get("BlockNumber", "") - - # 根据BlockNumber调整方量 - if block_number == "L2": - adjusted_volume = beton_volume + 0.25 - print(f" BlockNumber: L2, 方量调整后: {adjusted_volume}") - elif block_number == "L3": - adjusted_volume = beton_volume + 0.3 - print(f" BlockNumber: L3, 方量调整后: {adjusted_volume}") - else: - adjusted_volume = beton_volume - print(f" BlockNumber: {block_number}, 方量未调整") - - tasks.append({ - "beton_task_id": beton_task_id, - "beton_volume": adjusted_volume, - "artifact_id": artifact_id, - "block_number": block_number - }) - - 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 = "BCS7.2_SDBS" # 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() diff --git a/Allocation_api.py b/Allocation_api.py deleted file mode 100644 index 935bc64..0000000 --- a/Allocation_api.py +++ /dev/null @@ -1,445 +0,0 @@ -#从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() diff --git a/Flag.py b/Flag.py deleted file mode 100644 index 8b791a0..0000000 --- a/Flag.py +++ /dev/null @@ -1,36 +0,0 @@ -import pyodbc - -# 数据库连接信息 -db_path = "D:\\Janeoo-B12-DB\\Janeoo.2.mdb" # 替换为实际路径 -password = "BCS7.2_SDBS" # Access数据库密码 - - -def get_unique_flags_from_access(db_path, password): - conn_str = ( - r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};' - f'DBQ={db_path};' - f'PWD={password};' - ) - - try: - # 连接数据库 - conn = pyodbc.connect(conn_str) - cursor = conn.cursor() - - # 查询所有Flag字段的值 - cursor.execute("SELECT DISTINCT Flag FROM Produce") - flags = cursor.fetchall() - - # 输出结果 - print("唯一的Flag值:") - for flag in flags: - print(flag[0]) # flag[0]是查询结果中的第一个字段 - - conn.close() - - except Exception as e: - print(f"数据库操作失败: {e}") - - -# 调用函数 -get_unique_flags_from_access(db_path, password) diff --git a/InsertDataFlag.py b/InsertDataFlag.py deleted file mode 100644 index e231290..0000000 --- a/InsertDataFlag.py +++ /dev/null @@ -1,417 +0,0 @@ -import requests -import hashlib -import pyodbc -from datetime import datetime -import time -import json -import threading - -# 配置信息 -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() - - -# 计算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("获取任务单信息失败") - - -# 获取所有未浇筑信息 -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 = [] - for artifact in artifact_list: - beton_task_id = artifact["BetonTaskID"] - beton_volume = artifact["BetonVolume"] - artifact_id = artifact["ArtifactActionID"] - block_number = artifact.get("BlockNumber", "") - - # 根据BlockNumber调整方量 - if block_number == "L1": - adjusted_volume = beton_volume + 0.25 - print(f" BlockNumber: L1, 方量调整后: {adjusted_volume}") - elif block_number == "L2": - adjusted_volume = beton_volume + 0.3 - print(f" BlockNumber: L2, 方量调整后: {adjusted_volume}") - else: - adjusted_volume = beton_volume - print(f" BlockNumber: {block_number}, 方量未调整") - - tasks.append({ - "beton_task_id": beton_task_id, - "beton_volume": adjusted_volume, - "artifact_id": artifact_id, - "block_number": block_number - }) - - 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) - print(f"任务 {erp_id} (ArtifactID: {artifact_id}) 已添加到监控列表") - - return erp_id - - -# 监控Access数据库中特定任务的Flag字段变化 -def monitor_access_flag_changes(access_db_path, access_password): - """监控Access数据库中派发任务的Flag状态""" - - # 存储任务的当前状态 - task_flags = {} - - print("开始监控Access数据库中派发任务的Flag状态") - - 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删除的任务才需要在Access中查找 - if not deleted_from_sql_tasks: - continue - - # 连接Access数据库 - conn = connect_to_access_db(access_db_path, access_password) - cursor = conn.cursor() - - # 查询Access数据库中已删除任务的状态 - placeholders = ','.join('?' * len(list(deleted_from_sql_tasks))) - query = f"SELECT MISID, Flag FROM Produce WHERE MISID IN ({placeholders})" - - # 添加调试信息 - print(f"执行查询: {query}") - print(f"查询参数: {list(deleted_from_sql_tasks)}") - - cursor.execute(query, list(deleted_from_sql_tasks)) - results = cursor.fetchall() - - # 添加调试信息 - print(f"查询返回结果数量: {len(results)}") - - # 如果没有查询到结果,检查数据库中的实际数据 - if len(results) == 0 and deleted_from_sql_tasks: - print("未找到匹配记录,检查数据库中的实际数据:") - try: - cursor.execute("SELECT TOP 5 Mark, Flag FROM Produce ORDER BY Mark DESC") - sample_data = cursor.fetchall() - print(f"数据库中最近的5条记录: {sample_data}") - except Exception as sample_e: - print(f"查询样本数据时出错: {sample_e}") - - # 处理查询结果 - current_tasks = {} - for row in results: - mark = row[0] - flag = row[1] if row[1] is not None else "" - current_tasks[mark] = flag - print(f"查询到记录 - MISID: {mark}, Flag: '{flag}'") # 调试信息 - - # 检查每个已删除任务的状态变化 - for erp_id_str in deleted_from_sql_tasks: - erp_id = int(erp_id_str) - current_flag = current_tasks.get(erp_id_str, "") - previous_flag = task_flags.get(erp_id_str, "") - - # 添加调试信息 - print(f"检查任务 {erp_id} - 当前Flag: '{current_flag}', 之前Flag: '{previous_flag}'") - - # 如果状态发生变化 - if current_flag != previous_flag: - with tasks_lock: - artifact_id = inserted_tasks.get(erp_id, "Unknown") - print( - f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 的Flag值已更新: {previous_flag} -> {current_flag}") - task_flags[erp_id_str] = current_flag - - # 根据Flag值末尾的字母执行相应操作 - if current_flag.endswith('d'): - print(f"派发任务 ErpID {erp_id}: 未进行生产") - elif current_flag.endswith('w'): - print(f"派发任务 ErpID {erp_id}: 正在生产中") - elif current_flag.endswith('n'): - print(f"派发任务 ErpID {erp_id}: 生产完毕") - # 任务完成,可以从监控列表中移除 - with tasks_lock: - monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已完成,停止监控") - elif current_flag.endswith('p'): - print(f"派发任务 ErpID {erp_id}: 生产中断") - # 任务中断,可以从监控列表中移除 - with tasks_lock: - monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已中断,停止监控") - elif current_flag.endswith('x'): - print(f"派发任务 ErpID {erp_id}: 数据已接收") - - # 检查是否有任务记录已被删除(不在查询结果中但仍在监控列表中) - # 这表示任务可能已完成或从系统中移除 - missing_tasks = set(deleted_from_sql_tasks) - set(current_tasks.keys()) - if missing_tasks: - for erp_id_str in missing_tasks: - erp_id = int(erp_id_str) - with tasks_lock: - artifact_id = inserted_tasks.get(erp_id, "Unknown") - monitored_tasks.discard(erp_id) - inserted_tasks.pop(erp_id, None) - task_flags.pop(erp_id_str, None) - print(f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 记录已从Access数据库中删除或完成") - - conn.close() - - except Exception as e: - print(f"监控Access数据库 Flag时发生错误: {e}") - import traceback - traceback.print_exc() - continue - - -# 在 main 函数中修改任务处理逻辑 -def main(): - try: - # 步骤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 = "BCS7.2_SDBS" # Access数据库密码 - - # 启动Access数据库Flag监控线程 - 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("程序已停止") - - -if __name__ == "__main__": - main() diff --git a/InsertData_list.py b/InsertData_list.py new file mode 100644 index 0000000..96566f2 --- /dev/null +++ b/InsertData_list.py @@ -0,0 +1,898 @@ +import requests +import hashlib +import pyodbc +from datetime import datetime, timedelta +import time +import json +import threading +from tcp.server import TCPServer + +# 配置信息 +BASE_URL = "http://127.0.0.1:5000" # 外网地址"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() +artifact_timestamps = {} # 存储每个artifact_id的时间戳 + +# TCP服务端实例 +tcp_server = TCPServer +task_before = None # 用于存储上一条任务信息 +half_volume = [0, 0] + + +# 计算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"] + return task_data + raise Exception("获取任务单信息失败") + + +# 定期清理过期的时间戳记录 +def cleanup_old_timestamps(current_artifact_ids=None, max_age_hours=24): + """ + 清理过期的时间戳记录 + + Args: + current_artifact_ids: 当前活跃的artifact_id集合,可选 + max_age_hours: 时间戳最大保留时间(小时),默认24小时 + """ + current_time = datetime.now() + expired_ids = [] + + # 遍历所有存储的时间戳记录 + for artifact_id, timestamp in artifact_timestamps.items(): + # 如果提供了当前活跃ID列表,且该ID不在当前活跃列表中,则检查是否过期 + if current_artifact_ids is None or artifact_id not in current_artifact_ids: + age = current_time - timestamp + # 如果超过最大保留时间,则标记为过期 + if age.total_seconds() > max_age_hours * 3600: + expired_ids.append(artifact_id) + + # 删除过期的时间戳记录 + for artifact_id in expired_ids: + del artifact_timestamps[artifact_id] + + if expired_ids: + print(f"清理了 {len(expired_ids)} 个过期的时间戳记录: {expired_ids}") + + +# 获取所有未浇筑信息 +def get_all_not_pour_info(app_id): + """获取所有未浇筑信息并处理任务分发逻辑""" + global task_before, half_volume, artifact_timestamps + + headers = {"AppID": app_id} + response = requests.get(NOT_POUR_INFO_URL, headers=headers) + + if response.status_code != 200: + raise Exception("获取未浇筑信息网络请求失败") + + data = response.json() + if data.get("Code") != 200: + raise Exception("获取未浇筑信息API返回错误") + + artifact_list = data["Data"] + if not artifact_list: + return [], [], [], half_volume + + # 处理F块信息 + f_blocks_info = _process_f_blocks(artifact_list) + f_blocks = f_blocks_info["f_blocks"] + f_block_count = f_blocks_info["f_block_count"] + total_f_volume = f_blocks_info["total_f_volume"] + f_positions = f_blocks_info["f_positions"] + + # 处理当前任务 + current_task = _process_current_task(artifact_list[0], app_id) + + # 更新上一个任务信息 + task_before = { + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"] + } + + # 根据F块情况处理任务 + task_result = _handle_tasks_by_f_blocks( + f_block_count, f_positions, current_task, + f_blocks, total_f_volume, artifact_list, app_id + ) + + return task_result + + +def _process_f_blocks(artifact_list): + """处理F块相关信息""" + f_blocks = [artifact for artifact in artifact_list if artifact.get("BlockNumber") == "F"] + f_block_count = len(f_blocks) + total_f_volume = sum(artifact["BetonVolume"] for artifact in f_blocks) + f_positions = get_f_block_positions(artifact_list) + + return { + "f_blocks": f_blocks, + "f_block_count": f_block_count, + "total_f_volume": total_f_volume, + "f_positions": f_positions + } + + +def _process_current_task(latest_artifact, app_id): + """处理当前任务信息""" + return { + "beton_task_id": latest_artifact["BetonTaskID"], + "beton_volume": latest_artifact["BetonVolume"], + "artifact_id": latest_artifact["ArtifactActionID"], + "block_number": latest_artifact.get("BlockNumber", ""), + "task_data": get_task_info(app_id, latest_artifact["BetonTaskID"]) + } + + +def _handle_tasks_by_f_blocks(f_block_count, f_positions, current_task, + f_blocks, total_f_volume, artifact_list, app_id): + """根据F块数量和位置处理任务""" + + # 多个F块情况 + if f_block_count > 2: + return _handle_multiple_f_blocks(current_task, total_f_volume, artifact_list, app_id) + + # 两个F块情况 + elif f_block_count == 2: + return _handle_two_f_blocks(f_positions, current_task, total_f_volume, artifact_list, app_id) + + # 一个F块情况 + elif f_block_count == 1: + return _handle_single_f_block(f_positions, current_task, f_blocks, + total_f_volume, artifact_list, app_id) + + # 无F块情况 + elif f_block_count == 0: + return _handle_no_f_blocks(current_task, artifact_list, app_id) + + else: + print("报警") + return [], [], [], half_volume + + +def _handle_multiple_f_blocks(current_task, total_f_volume, artifact_list, app_id): + """处理多个F块的情况""" + adjusted_volume = total_f_volume - half_volume[0] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + _append_additional_tasks(send_list, artifact_list, app_id, [0, 0]) + + # 更新时间戳 + _update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, half_volume + + +def _handle_two_f_blocks(f_positions, current_task, total_f_volume, artifact_list, app_id): + """处理两个F块的情况""" + if f_positions == [0, 1] and task_before.get("block_number") == "F": + adjusted_volume = 0 + block_number = "补方" + else: + adjusted_volume = total_f_volume - half_volume[0] + block_number = current_task["block_number"] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + volumes = [adjusted_volume, artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0] if f_positions == [0, + 1] and task_before.get( + "block_number") == "F" else [0, 0] + _append_additional_tasks(send_list, artifact_list, app_id, volumes) + + # 更新时间戳 + _update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, half_volume + + +def _handle_single_f_block(f_positions, current_task, f_blocks, total_f_volume, artifact_list, app_id): + """处理单个F块的情况""" + if f_positions == [2]: + f_volume = f_blocks[0].get("BetonVolume") if f_blocks else 0 + half_volume[0] = round(total_f_volume / 2, 2) + half_volume[1] = f_volume - half_volume[0] + adjusted_volume = current_task["beton_volume"] + half_volume[0] + elif f_positions == [1]: + adjusted_volume = current_task["beton_volume"] + half_volume[1] + elif f_positions == [0]: + adjusted_volume = 0 + else: + adjusted_volume = current_task["beton_volume"] + + block_number = "补方" if f_positions == [0] else current_task["block_number"] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + _append_additional_tasks_for_single_f(send_list, artifact_list, app_id, f_positions) + + # 更新时间戳 + _update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, half_volume + + +def _handle_no_f_blocks(current_task, artifact_list, app_id): + """处理无F块的情况""" + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + _append_additional_tasks(send_list, artifact_list, app_id, + [artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0, + artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0]) + + # 更新时间戳 + _update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, half_volume + + +def _append_additional_tasks(send_list, artifact_list, app_id, volumes): + """添加额外的任务到发送列表""" + # 安全获取后续任务 + second_task = artifact_list[1] if len(artifact_list) > 1 else None + third_task = artifact_list[2] if len(artifact_list) > 2 else None + + if second_task: + task_data_second = get_task_info(app_id, second_task["BetonTaskID"]) + send_list.append({ + "beton_task_id": second_task["BetonTaskID"], + "beton_volume": volumes[0], + "artifact_id": second_task["ArtifactActionID"], + "block_number": second_task["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(second_task["ArtifactActionID"], datetime.now()) + }) + + if third_task: + task_data_third = get_task_info(app_id, third_task["BetonTaskID"]) + send_list.append({ + "beton_task_id": third_task["BetonTaskID"], + "beton_volume": volumes[1], + "artifact_id": third_task["ArtifactActionID"], + "block_number": third_task["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(third_task["ArtifactActionID"], datetime.now()) + }) + + +def _append_additional_tasks_for_single_f(send_list, artifact_list, app_id, f_positions): + """为单个F块情况添加额外任务""" + second_task = artifact_list[1] if len(artifact_list) > 1 else None + third_task = artifact_list[2] if len(artifact_list) > 2 else None + + if second_task: + task_data_second = get_task_info(app_id, second_task["BetonTaskID"]) + volume = (third_task["BetonVolume"] if third_task else 0) if f_positions != [2] else ( + second_task["BetonVolume"] + half_volume[1]) + send_list.append({ + "beton_task_id": second_task["BetonTaskID"], + "beton_volume": volume, + "artifact_id": second_task["ArtifactActionID"], + "block_number": second_task["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(second_task["ArtifactActionID"], datetime.now()) + }) + + if third_task: + task_data_third = get_task_info(app_id, third_task["BetonTaskID"]) + volume = third_task["BetonVolume"] if f_positions in [[1], [0]] else 0 + send_list.append({ + "beton_task_id": third_task["BetonTaskID"], + "beton_volume": volume, + "artifact_id": third_task["ArtifactActionID"], + "block_number": third_task["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(third_task["ArtifactActionID"], datetime.now()) + }) + + +def _update_artifact_timestamps(send_list): + """更新artifact时间戳""" + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + + +def get_f_block_positions(artifact_list): + """获取artifact_list中F块的位置""" + positions = [] + for i, artifact in enumerate(artifact_list): + if artifact.get("BlockNumber") == "F": + positions.append(i) + return positions + + +# 连接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表 +# 在 insert_into_produce_table 函数中添加调用同事的保存函数 +def insert_into_produce_table(connection, task_info, beton_volume, erp_id, artifact_id, status): + cursor = connection.cursor() + if status == "1": + # 准备插入数据 + 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) + print(f"任务 {erp_id} (ArtifactID: {artifact_id}) 已添加到监控列表") + + # 调用同事提供的保存函数,将数据保存到自定义数据表 + try: + # 假设同事提供的函数名为 save_to_custom_table + # 参数包括: MISID(即erp_id), Flag, TaskID, ProduceMixID, ProjectName, BetonGrade, 调整后的方量 + 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, + artifact_id=artifact_id + # 已经调整后的方量 + ) + print(f"任务 {erp_id} 的数据已保存到自定义数据表") + except Exception as e: + print(f"调用保存函数时出错: {e}") + + # 发送数据给TCP客户端 + try: + time.sleep(5) + task_data = { + "erp_id": erp_id, # 车号,相当于序号 + "task_id": task_info["TaskID"], # 任务单号 + "artifact_id": artifact_id, + "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 + else: + try: + # 假设同事提供的函数名为 save_to_custom_table + # 参数包括: MISID(即erp_id), Flag, TaskID, ProduceMixID, ProjectName, BetonGrade, 调整后的方量 + 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, + artifact_id=artifact_id + ) + print(f"任务 {erp_id} 的数据已保存到自定义数据表") + except Exception as e: + print(f"调用保存函数时出错: {e}") + + +# 监控Access数据库中特定任务的Flag字段变化 +def monitor_access_flag_changes(access_db_path, access_password): + """监控Access数据库中派发任务的Flag状态""" + + # 存储任务的当前状态 + task_flags = {} + + print("开始监控Access数据库中派发任务的Flag状态") + + 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删除的任务才需要在Access中查找 + if not deleted_from_sql_tasks: + continue + + # 连接Access数据库 + conn = connect_to_access_db(access_db_path, access_password) + cursor = conn.cursor() + + # 查询Access数据库中已删除任务的状态 + placeholders = ','.join('?' * len(list(deleted_from_sql_tasks))) + query = f"SELECT MISID, Flag FROM Produce WHERE MISID IN ({placeholders})" + + # 添加调试信息 + print(f"执行查询: {query}") + print(f"查询参数: {list(deleted_from_sql_tasks)}") + + cursor.execute(query, list(deleted_from_sql_tasks)) + results = cursor.fetchall() + + # 添加调试信息 + print(f"查询返回结果数量: {len(results)}") + + # 如果没有查询到结果,检查数据库中的实际数据 + if len(results) == 0 and deleted_from_sql_tasks: + print("未找到匹配记录,检查数据库中的实际数据:") + try: + cursor.execute("SELECT TOP 5 Mark, Flag FROM Produce ORDER BY Mark DESC") + sample_data = cursor.fetchall() + print(f"数据库中最近的5条记录: {sample_data}") + except Exception as sample_e: + print(f"查询样本数据时出错: {sample_e}") + + # 处理查询结果 + current_tasks = {} + for row in results: + mark = row[0] + flag = row[1] if row[1] is not None else "" + current_tasks[mark] = flag + print(f"查询到记录 - MISID: {mark}, Flag: '{flag}'") # 调试信息 + + # 检查每个已删除任务的状态变化 + for erp_id_str in deleted_from_sql_tasks: + erp_id = int(erp_id_str) + current_flag = current_tasks.get(erp_id_str, "") + previous_flag = task_flags.get(erp_id_str, "") + + # 添加调试信息 + print(f"检查任务 {erp_id} - 当前Flag: '{current_flag}', 之前Flag: '{previous_flag}'") + + # 如果状态发生变化 + if current_flag != previous_flag: # 添加这行 + with tasks_lock: + artifact_id = inserted_tasks.get(erp_id, "Unknown") + print( + f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 的Flag值已更新: {previous_flag} -> {current_flag}") + task_flags[erp_id_str] = current_flag + + # 根据Flag值末尾的字母执行相应操作并更新自定义数据表状态 + if current_flag.endswith('d'): # 将 elif 改为 if + print(f"派发任务 ErpID {erp_id}: 未进行生产") + # 调用同事提供的状态更新函数 + try: + print(1) + # update_custom_table_status(erp_id, "未进行生产") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "未进行生产" + } + tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + # 在"正在生产中"分支中: + elif current_flag.endswith('w'): + print(f"派发任务 ErpID {erp_id}: 正在生产中") + # 调用同事提供的状态更新函数 + try: + print(2) + # update_custom_table_status(erp_id, "正在生产中") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "正在生产中" + } + tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + # 在"生产完毕"分支中: + elif current_flag.endswith('n'): + print(f"派发任务 ErpID {erp_id}: 生产完毕") + # 任务完成,可以从监控列表中移除 + with tasks_lock: + monitored_tasks.discard(erp_id) + print(f"派发任务 ErpID {erp_id} 已完成,停止监控") + # 调用同事提供的状态更新函数 + try: + print(3) + # update_custom_table_status(erp_id, "生产完毕") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "生产完毕" + } + tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + # 在"生产中断"分支中: + elif current_flag.endswith('p'): + print(f"派发任务 ErpID {erp_id}: 生产中断") + # 任务中断,可以从监控列表中移除 + with tasks_lock: + monitored_tasks.discard(erp_id) + print(f"派发任务 ErpID {erp_id} 已中断,停止监控") + # 调用同事提供的状态更新函数 + try: + print(4) + # update_custom_table_status(erp_id, "生产中断") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "生产中断" + } + tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + # 在"数据已接收"分支中: + elif current_flag.endswith('x'): + print(f"派发任务 ErpID {erp_id}: 数据已接收") + # 调用同事提供的状态更新函数 + try: + print(5) + update_custom_table_status(erp_id, "数据已接收") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "数据已接收" + } + tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + # 检查是否有任务记录已被删除(不在查询结果中但仍在监控列表中) + # 这表示任务可能已完成或从系统中移除 + missing_tasks = set(deleted_from_sql_tasks) - set(current_tasks.keys()) + if missing_tasks: + for erp_id_str in missing_tasks: + erp_id = int(erp_id_str) + with tasks_lock: + artifact_id = inserted_tasks.get(erp_id, "Unknown") + monitored_tasks.discard(erp_id) + inserted_tasks.pop(erp_id, None) + task_flags.pop(erp_id_str, None) + print(f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 记录已从Access数据库中删除或完成") + + conn.close() + + except Exception as e: + print(f"监控Access数据库 Flag时发生错误: {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() + last_artifact_list = [] # 用于存储上一次的完整artifact_list + + # Access数据库路径和密码 + access_db_path = "D:\\Janeoo-B12-DB\\Janeoo.2.mdb" # 替换为实际路径 + access_password = "BCS7.2_SDBS" # Access数据库密码 + + # 启动Access数据库Flag监控线程 + 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, artifact_list, send_list, half_volume = get_all_not_pour_info(app_id) + print(tasks) + print(artifact_list) + print(send_list) + print(half_volume) + current_artifact_ids = {task["artifact_id"] for task in tasks} + + # 检查artifact_list是否发生变化 + if artifact_list != last_artifact_list: + print(f"检测到artifact_list更新: {artifact_list}") + + # 处理新出现的任务 + 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: + 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() + # 检查 block_number 是否为 "F" + if task["block_number"] == "补方": + print(f"任务 {task['artifact_id']} 的 block_number 为 '补方',跳过派单") + insert_into_produce_table(connection, task_info, task["beton_volume"], erp_id, + task["artifact_id"], 0) + connection.close() + continue + + print(f"处理新任务: {task['artifact_id']}") + + # 步骤3:获取任务单信息 + insert_into_produce_table(connection, task_info, task["beton_volume"], erp_id, + task["artifact_id"], 1) + connection.close() + + # 更新上次获取的ArtifactID集合和artifact_list + last_artifact_ids = current_artifact_ids + last_artifact_list = artifact_list.copy() # 保存当前的artifact_list + + # 每10分钟清理一次过期的时间戳记录 + cleanup_old_timestamps(current_artifact_ids, max_age_hours=24) + + # 每10秒检查一次 + time.sleep(10) + + except Exception as e: + print(f"发生错误: {e}") + # 继续循环,避免程序退出 + time.sleep(2) + + except KeyboardInterrupt: + print("程序已停止") + # 停止TCP服务端 + if tcp_server: + tcp_server.stop() + + +if __name__ == "__main__": + main() diff --git a/InsertData_tran.py b/InsertData_tran.py deleted file mode 100644 index 2df279c..0000000 --- a/InsertData_tran.py +++ /dev/null @@ -1,561 +0,0 @@ -#在线版本,实时监控Flag信息,但是还没有实现每次只取最上面那条 - -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 = TCPServer - - -# 计算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("获取任务单信息失败") - - -# 获取所有未浇筑信息 -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 = [] - for artifact in artifact_list: - beton_task_id = artifact["BetonTaskID"] - beton_volume = artifact["BetonVolume"] - artifact_id = artifact["ArtifactActionID"] - block_number = artifact.get("BlockNumber", "") - - # 根据BlockNumber调整方量 - if block_number == "L2": - adjusted_volume = beton_volume + 0.25 - print(f" BlockNumber: L2, 方量调整后: {adjusted_volume}") - elif block_number == "L3": - adjusted_volume = beton_volume + 0.3 - print(f" BlockNumber: L3, 方量调整后: {adjusted_volume}") - else: - adjusted_volume = beton_volume - print(f" BlockNumber: {block_number}, 方量未调整") - - tasks.append({ - "beton_task_id": beton_task_id, - "beton_volume": adjusted_volume, - "artifact_id": artifact_id, - "block_number": block_number - }) - - 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表 -# 在 insert_into_produce_table 函数中添加调用同事的保存函数 -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) - print(f"任务 {erp_id} (ArtifactID: {artifact_id}) 已添加到监控列表") - - # 调用同事提供的保存函数,将数据保存到自定义数据表 - try: - # 假设同事提供的函数名为 save_to_custom_table - # 参数包括: MISID(即erp_id), Flag, TaskID, ProduceMixID, ProjectName, BetonGrade, 调整后的方量 - # 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} 的数据已保存到自定义数据表") - except Exception as e: - print(f"调用保存函数时出错: {e}") - - # 发送数据给TCP客户端 - try: - time.sleep(5) - 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 - - -# 监控Access数据库中特定任务的Flag字段变化 -def monitor_access_flag_changes(access_db_path, access_password): - """监控Access数据库中派发任务的Flag状态""" - - # 存储任务的当前状态 - task_flags = {} - - print("开始监控Access数据库中派发任务的Flag状态") - - 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删除的任务才需要在Access中查找 - if not deleted_from_sql_tasks: - continue - - # 连接Access数据库 - conn = connect_to_access_db(access_db_path, access_password) - cursor = conn.cursor() - - # 查询Access数据库中已删除任务的状态 - placeholders = ','.join('?' * len(list(deleted_from_sql_tasks))) - query = f"SELECT MISID, Flag FROM Produce WHERE MISID IN ({placeholders})" - - # 添加调试信息 - print(f"执行查询: {query}") - print(f"查询参数: {list(deleted_from_sql_tasks)}") - - cursor.execute(query, list(deleted_from_sql_tasks)) - results = cursor.fetchall() - - # 添加调试信息 - print(f"查询返回结果数量: {len(results)}") - - # 如果没有查询到结果,检查数据库中的实际数据 - if len(results) == 0 and deleted_from_sql_tasks: - print("未找到匹配记录,检查数据库中的实际数据:") - try: - cursor.execute("SELECT TOP 5 Mark, Flag FROM Produce ORDER BY Mark DESC") - sample_data = cursor.fetchall() - print(f"数据库中最近的5条记录: {sample_data}") - except Exception as sample_e: - print(f"查询样本数据时出错: {sample_e}") - - # 处理查询结果 - current_tasks = {} - for row in results: - mark = row[0] - flag = row[1] if row[1] is not None else "" - current_tasks[mark] = flag - print(f"查询到记录 - MISID: {mark}, Flag: '{flag}'") # 调试信息 - - # 检查每个已删除任务的状态变化 - for erp_id_str in deleted_from_sql_tasks: - erp_id = int(erp_id_str) - current_flag = current_tasks.get(erp_id_str, "") - previous_flag = task_flags.get(erp_id_str, "") - - # 添加调试信息 - print(f"检查任务 {erp_id} - 当前Flag: '{current_flag}', 之前Flag: '{previous_flag}'") - - # 如果状态发生变化 - if current_flag != previous_flag: # 添加这行 - with tasks_lock: - artifact_id = inserted_tasks.get(erp_id, "Unknown") - print( - f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 的Flag值已更新: {previous_flag} -> {current_flag}") - task_flags[erp_id_str] = current_flag - - # 根据Flag值末尾的字母执行相应操作并更新自定义数据表状态 - if current_flag.endswith('d'): # 将 elif 改为 if - print(f"派发任务 ErpID {erp_id}: 未进行生产") - # 调用同事提供的状态更新函数 - try: - print(1) - # update_custom_table_status(erp_id, "未进行生产") - except Exception as e: - print(f"更新状态时出错: {e}") - - # 发送数据给TCP客户端(只发送erp_id和状态) - try: - status_data = { - "erp_id": erp_id, - "status": "未进行生产" - } - tcp_server.send_data(status_data) - except Exception as e: - print(f"发送状态数据给TCP客户端时出错: {e}") - - # 在"正在生产中"分支中: - elif current_flag.endswith('w'): - print(f"派发任务 ErpID {erp_id}: 正在生产中") - # 调用同事提供的状态更新函数 - try: - print(2) - # update_custom_table_status(erp_id, "正在生产中") - except Exception as e: - print(f"更新状态时出错: {e}") - - # 发送数据给TCP客户端(只发送erp_id和状态) - try: - status_data = { - "erp_id": erp_id, - "status": "正在生产中" - } - tcp_server.send_data(status_data) - except Exception as e: - print(f"发送状态数据给TCP客户端时出错: {e}") - - # 在"生产完毕"分支中: - elif current_flag.endswith('n'): - print(f"派发任务 ErpID {erp_id}: 生产完毕") - # 任务完成,可以从监控列表中移除 - with tasks_lock: - monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已完成,停止监控") - # 调用同事提供的状态更新函数 - try: - print(3) - # update_custom_table_status(erp_id, "生产完毕") - except Exception as e: - print(f"更新状态时出错: {e}") - - # 发送数据给TCP客户端(只发送erp_id和状态) - try: - status_data = { - "erp_id": erp_id, - "status": "生产完毕" - } - tcp_server.send_data(status_data) - except Exception as e: - print(f"发送状态数据给TCP客户端时出错: {e}") - - # 在"生产中断"分支中: - elif current_flag.endswith('p'): - print(f"派发任务 ErpID {erp_id}: 生产中断") - # 任务中断,可以从监控列表中移除 - with tasks_lock: - monitored_tasks.discard(erp_id) - print(f"派发任务 ErpID {erp_id} 已中断,停止监控") - # 调用同事提供的状态更新函数 - try: - print(4) - # update_custom_table_status(erp_id, "生产中断") - except Exception as e: - print(f"更新状态时出错: {e}") - - # 发送数据给TCP客户端(只发送erp_id和状态) - try: - status_data = { - "erp_id": erp_id, - "status": "生产中断" - } - tcp_server.send_data(status_data) - except Exception as e: - print(f"发送状态数据给TCP客户端时出错: {e}") - - # 在"数据已接收"分支中: - elif current_flag.endswith('x'): - print(f"派发任务 ErpID {erp_id}: 数据已接收") - # 调用同事提供的状态更新函数 - try: - print(5) - # update_custom_table_status(erp_id, "数据已接收") - except Exception as e: - print(f"更新状态时出错: {e}") - - # 发送数据给TCP客户端(只发送erp_id和状态) - try: - status_data = { - "erp_id": erp_id, - "status": "数据已接收" - } - tcp_server.send_data(status_data) - except Exception as e: - print(f"发送状态数据给TCP客户端时出错: {e}") - - # 检查是否有任务记录已被删除(不在查询结果中但仍在监控列表中) - # 这表示任务可能已完成或从系统中移除 - missing_tasks = set(deleted_from_sql_tasks) - set(current_tasks.keys()) - if missing_tasks: - for erp_id_str in missing_tasks: - erp_id = int(erp_id_str) - with tasks_lock: - artifact_id = inserted_tasks.get(erp_id, "Unknown") - monitored_tasks.discard(erp_id) - inserted_tasks.pop(erp_id, None) - task_flags.pop(erp_id_str, None) - print(f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 记录已从Access数据库中删除或完成") - - conn.close() - - except Exception as e: - print(f"监控Access数据库 Flag时发生错误: {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 = "BCS7.2_SDBS" # Access数据库密码 - - # 启动Access数据库Flag监控线程 - 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() diff --git a/__pycache__/TCPServer.cpython-312.pyc b/__pycache__/TCPServer.cpython-312.pyc deleted file mode 100644 index 72d9cd0..0000000 Binary files a/__pycache__/TCPServer.cpython-312.pyc and /dev/null differ diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/config/__pycache__/__init__.cpython-39.pyc b/config/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..62c663c Binary files /dev/null and b/config/__pycache__/__init__.cpython-39.pyc differ diff --git a/config/__pycache__/settings.cpython-39.pyc b/config/__pycache__/settings.cpython-39.pyc new file mode 100644 index 0000000..618bb99 Binary files /dev/null and b/config/__pycache__/settings.cpython-39.pyc differ diff --git a/config/settings.py b/config/settings.py new file mode 100644 index 0000000..9d8c5db --- /dev/null +++ b/config/settings.py @@ -0,0 +1,32 @@ +"""配置信息模块""" +import os + +# API配置 +BASE_URL = "http://127.0.0.1:5000"#https://www.shnthy.com:9154 +LOGIN_DATA = { + "Program": 11, + "SC": "1000000001", + "loginName": "leduser", + "password": "bfcda35cf4eba92d4583931bbe4ff72ffdfa8b5c9c4b72611bd33f5babee069d" +} + +# 数据库配置 +ACCESS_DB_PATH = "D:\\Janeoo-B12-DB\\Janeoo.2.mdb" +ACCESS_DB_PASSWORD = "BCS7.2_SDBS" + +SQL_SERVER_CONFIG = { + "driver": "{SQL Server}", + "server": "127.0.0.1", + "database": "BS23DB", + "username": "sa", + "password": "123" +} + +# TCP配置 +TCP_HOST = '127.0.0.1' +TCP_PORT = 8888 + +# 其他配置 +MAX_AGE_HOURS = 24 +CHECK_INTERVAL = 10 +MONITOR_INTERVAL = 2 diff --git a/database/__init__.py b/database/__init__.py new file mode 100644 index 0000000..255bfcf --- /dev/null +++ b/database/__init__.py @@ -0,0 +1,5 @@ +"""数据库包""" +from .access_db import AccessDB +from .sql_server import SQLServerDB + +__all__ = ['AccessDB', 'SQLServerDB'] diff --git a/database/__pycache__/__init__.cpython-39.pyc b/database/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..81602cf Binary files /dev/null and b/database/__pycache__/__init__.cpython-39.pyc differ diff --git a/database/__pycache__/access_db.cpython-39.pyc b/database/__pycache__/access_db.cpython-39.pyc new file mode 100644 index 0000000..ec5f3a8 Binary files /dev/null and b/database/__pycache__/access_db.cpython-39.pyc differ diff --git a/database/__pycache__/sql_server.cpython-39.pyc b/database/__pycache__/sql_server.cpython-39.pyc new file mode 100644 index 0000000..e6bcab9 Binary files /dev/null and b/database/__pycache__/sql_server.cpython-39.pyc differ diff --git a/database/__pycache__/sql_server_connection.cpython-39.pyc b/database/__pycache__/sql_server_connection.cpython-39.pyc new file mode 100644 index 0000000..3364fb5 Binary files /dev/null and b/database/__pycache__/sql_server_connection.cpython-39.pyc differ diff --git a/database/access_db.py b/database/access_db.py new file mode 100644 index 0000000..c2cd908 --- /dev/null +++ b/database/access_db.py @@ -0,0 +1,61 @@ +"""Access数据库操作模块""" +import pyodbc + + +class AccessDB: + def __init__(self, db_path, password): + self.db_path = db_path + self.password = password + self.connection = None + + def connect(self): + """连接Access数据库""" + conn_str = ( + r'DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};' + f'DBQ={self.db_path};' + f'PWD={self.password};' + ) + self.connection = pyodbc.connect(conn_str) + return self.connection + + def get_max_mark(self): + """获取Access数据库中最大的Mark值""" + if not self.connection: + self.connect() + + cursor = self.connection.cursor() + cursor.execute("SELECT MAX(Mark) FROM Produce") + max_mark = cursor.fetchone()[0] + + if max_mark is None: + max_mark = 0 + + return max_mark + + def query_task_status(self, mis_ids): + """查询任务状态""" + if not self.connection: + self.connect() + + if not mis_ids: + return {} + + cursor = self.connection.cursor() + placeholders = ','.join('?' * len(mis_ids)) + query = f"SELECT MISID, Flag FROM Produce WHERE MISID IN ({placeholders})" + cursor.execute(query, mis_ids) + results = cursor.fetchall() + + current_tasks = {} + for row in results: + mark = row[0] + flag = row[1] if row[1] is not None else "" + current_tasks[mark] = flag + + return current_tasks + + def close(self): + """关闭数据库连接""" + if self.connection: + self.connection.close() + self.connection = None diff --git a/database/sql_server.py b/database/sql_server.py new file mode 100644 index 0000000..0290803 --- /dev/null +++ b/database/sql_server.py @@ -0,0 +1,61 @@ +"""SQL Server数据库操作模块""" +import pyodbc +from config.settings import SQL_SERVER_CONFIG + + +class SQLServerDB: + def __init__(self): + self.connection = None + self.config = SQL_SERVER_CONFIG + + def connect(self): + """连接SQL Server数据库""" + connection_string = ( + "DRIVER={SQL Server};" + f"SERVER={self.config['server']};" + f"DATABASE={self.config['database']};" + f"UID={self.config['username']};" + f"PWD={self.config['password']};" + ) + self.connection = pyodbc.connect(connection_string) + return self.connection + + def insert_produce_data(self, insert_data): + """插入数据到Produce表""" + if not self.connection: + self.connect() + + cursor = self.connection.cursor() + 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())) + self.connection.commit() + + return cursor.rowcount + + def check_existing_tasks(self, erp_ids): + """检查SQL Server中任务是否还存在""" + if not self.connection: + self.connect() + + if not erp_ids: + return set() + + 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})" + + cursor = self.connection.cursor() + cursor.execute(check_query, erp_ids_str) + results = cursor.fetchall() + + existing_tasks = {str(row[0]) for row in results} + return existing_tasks + + def close(self): + """关闭数据库连接""" + if self.connection: + self.connection.close() + self.connection = None diff --git a/database/sql_server_connection.py b/database/sql_server_connection.py new file mode 100644 index 0000000..55c9565 --- /dev/null +++ b/database/sql_server_connection.py @@ -0,0 +1,63 @@ +# database/sql_server_connection.py +"""SQL Server数据库连接模块""" +import pyodbc +from config.settings import SQL_SERVER_CONFIG + +class SQLServerConnection: + def __init__(self): + self.config = SQL_SERVER_CONFIG + + def connect(self): + """建立数据库连接""" + connection_string = ( + f"DRIVER={self.config['driver']};" + f"SERVER={self.config['server']};" + f"DATABASE={self.config['database']};" + f"UID={self.config['username']};" + f"PWD={self.config['password']};" + ) + return pyodbc.connect(connection_string) + + def get_mix_weight_info(self): + """ + 获取所有配比号及其对应每方重量的信息 + 重量计算方式:U1到U17的和,NULL值不计入 + """ + connection = self.connect() + cursor = connection.cursor() + + try: + # 查询所有配比信息 + query = """ + SELECT + Code, + U1, U2, U3, U4, U5, U6, U7, U8, U9, U10, U11, U12, U13, U14, U15, U16, U17 + FROM MixTable + WHERE Code IS NOT NULL + ORDER BY Code + """ + + cursor.execute(query) + results = cursor.fetchall() + + mix_info = [] + for row in results: + code = row[0] + weights = [row[i] for i in range(1, 18)] # U1到U17 + + # 计算总重量(忽略NULL值) + total_weight = sum(weight for weight in weights if weight is not None and weight != 'NULL') + + mix_info.append({ + "Code": code, + "TotalWeight": round(total_weight, 2) # 保留两位小数 + }) + + return mix_info + + except Exception as e: + print(f"查询配比信息时出错: {e}") + return [] + + finally: + connection.close() diff --git a/insertData.py b/insertData.py deleted file mode 100644 index 358a683..0000000 --- a/insertData.py +++ /dev/null @@ -1,224 +0,0 @@ -import requests -import pyodbc -from datetime import datetime -import time - -# 配置信息 -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" -} - - -# 计算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("获取任务单信息失败") - - -# 获取未浇筑信息(新增) -def get_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"] - if len(artifact_list) > 0: - first_artifact = artifact_list[0] # 获取第一个元素 - beton_task_id = first_artifact["BetonTaskID"] - beton_volume = first_artifact["BetonVolume"] - artifact_id = first_artifact["ArtifactActionID"] # 获取ArtifactID - print(f"获取到BetonTaskID: {beton_task_id}") - print(f"获取到BetonVolume: {beton_volume}") - print(f"获取到ArtifactActionID: {artifact_id}") - return beton_task_id, beton_volume, artifact_id - else: - raise Exception("未找到未浇筑信息") - 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): - 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表中") - - -# 主函数 -def main(): - try: - # 步骤1:获取AppID - app_id = get_app_id() - - # 上次获取的ArtifactID,用于检测变化 - last_artifact_id = None - - # Access数据库路径和密码 - access_db_path = "D:\\Janeoo-B12-DB\\Janeoo.2.mdb" # 替换为实际路径 - access_password = "BCS7.2_SDBS" # Access数据库密码 - - while True: - try: - # 步骤2:获取未浇筑信息中的BetonTaskID、BetonVolume和ArtifactID - beton_task_id, beton_volume, artifact_id = get_not_pour_info(app_id) - # beton_task_id = "20251016-01" - - # 检查ArtifactID是否发生变化 - if artifact_id != last_artifact_id: - print(f"检测到新任务: {artifact_id}") - - # 步骤3:使用BetonTaskID获取任务单信息 - task_info = get_task_info(app_id, beton_task_id) - - # 步骤4:连接Access数据库并获取最大Mark值 - max_mark = get_max_mark_from_access(access_db_path, access_password) - erp_id = int(max_mark) + 1 # 在最大Mark值基础上加1 - print(f"获取到ERP ID: {erp_id}") - - # 步骤5:连接SQL Server数据库并插入数据 - connection = connect_to_sql_server() - insert_into_produce_table(connection, task_info, beton_volume, erp_id) - connection.close() - - # 更新上次获取的ArtifactID - last_artifact_id = artifact_id - - # 每2秒检查一次 - time.sleep(2) - - except Exception as e: - print(f"发生错误: {e}") - # 继续循环,避免程序退出 - time.sleep(2) - - except KeyboardInterrupt: - print("程序已停止") - - -if __name__ == "__main__": - main() diff --git a/main.py b/main.py new file mode 100644 index 0000000..f07040f --- /dev/null +++ b/main.py @@ -0,0 +1,132 @@ +"""主程序入口""" +import time +import threading +from datetime import datetime +from API.client import APIClient +from API.mix_weight_api import MixWeightAPI +from services.task_service import TaskService +from services.monitoring_service import MonitoringService +from database.access_db import AccessDB +from database.sql_server import SQLServerDB +from tcp.server import TCPServer +from config.settings import ( + ACCESS_DB_PATH, ACCESS_DB_PASSWORD, + TCP_HOST, TCP_PORT, CHECK_INTERVAL, MAX_AGE_HOURS +) +from utils.helpers import cleanup_old_timestamps + +def start_api_service(): + """启动配比重量API服务""" + api = MixWeightAPI() + api.run(host='127.0.0.1', port=5001, debug=False, threaded=True) + +def main(): + api_thread = threading.Thread(target=start_api_service) + api_thread.daemon = True + api_thread.start() + try: + # 初始化TCP服务端 + tcp_server = TCPServer(host=TCP_HOST, port=TCP_PORT) + tcp_server_thread = threading.Thread(target=tcp_server.start) + tcp_server_thread.daemon = True + tcp_server_thread.start() + + # 等待服务端启动 + time.sleep(1) + + # 初始化服务 + api_client = APIClient() + task_service = TaskService() + monitoring_service = MonitoringService(tcp_server) + + # 步骤1:获取AppID + app_id = api_client.login() + task_service.api_client.app_id = app_id + + # 存储上次获取的所有ArtifactID + last_artifact_ids = set() + last_artifact_list = [] # 用于存储上一次的完整artifact_list + + # 启动Access数据库Flag监控线程 + access_monitor_thread = threading.Thread(target=monitoring_service.monitor_access_flag_changes) + access_monitor_thread.daemon = True + access_monitor_thread.start() + + while True: + try: + # 步骤2:获取所有未浇筑信息 + tasks, artifact_list, send_list, half_volume = task_service.process_not_pour_info() + current_artifact_ids = {task["artifact_id"] for task in tasks} + + # 检查artifact_list是否发生变化 + if artifact_list != last_artifact_list: + print(f"检测到artifact_list更新: {artifact_list}") + + # 处理新出现的任务 + 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: + task_info = api_client.get_task_info(task["beton_task_id"]) + + # 步骤4:连接Access数据库并获取最大Mark值 + access_db = AccessDB(ACCESS_DB_PATH, ACCESS_DB_PASSWORD) + try: + max_mark = access_db.get_max_mark() + finally: + access_db.close() + + erp_id = int(max_mark) + 1 + + # 步骤5:连接SQL Server数据库并插入数据 + sql_db = SQLServerDB() + try: + # 准备插入数据 + insert_data = { + "ErpID": erp_id, + "Code": task_info["TaskID"], + "DatTim": datetime.now(), + "Recipe": task_info["ProduceMixID"], + "MorRec": "", + "ProdMete": task["beton_volume"], + "MorMete": 0.0, + "TotVehs": 0, + "TotMete": task_info["PlannedVolume"], + "Qualitor": "", + "Acceptor": "", + "Attamper": "", + "Flag": "1", + "Note": "" + } + + sql_db.insert_produce_data(insert_data) + print(f"数据已成功插入到Produce表中,ERP ID: {erp_id}") + finally: + sql_db.close() + + # 更新上次获取的ArtifactID集合和artifact_list + last_artifact_ids = current_artifact_ids + last_artifact_list = artifact_list.copy() + + # 每10分钟清理一次过期的时间戳记录 + cleanup_old_timestamps(task_service.artifact_timestamps, current_artifact_ids, MAX_AGE_HOURS) + + # 每10秒检查一次 + time.sleep(CHECK_INTERVAL) + + except Exception as e: + print(f"发生错误: {e}") + # 继续循环,避免程序退出 + time.sleep(2) + + except KeyboardInterrupt: + print("程序已停止") + # 停止TCP服务端 + if 'tcp_server' in locals(): + tcp_server.stop() + + +if __name__ == "__main__": + main() diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..36fc1f9 --- /dev/null +++ b/models/__init__.py @@ -0,0 +1,4 @@ +"""模型包""" +from .task import Task, SendTask + +__all__ = ['Task', 'SendTask'] diff --git a/models/task.py b/models/task.py new file mode 100644 index 0000000..bb33d89 --- /dev/null +++ b/models/task.py @@ -0,0 +1,20 @@ +"""任务相关数据模型""" +from datetime import datetime + +class Task: + def __init__(self, beton_task_id, beton_volume, artifact_id, block_number): + self.beton_task_id = beton_task_id + self.beton_volume = beton_volume + self.artifact_id = artifact_id + self.block_number = block_number + +class SendTask: + def __init__(self, beton_task_id, beton_volume, artifact_id, block_number, + beton_grade, mix_id, timestamp=None): + self.beton_task_id = beton_task_id + self.beton_volume = beton_volume + self.artifact_id = artifact_id + self.block_number = block_number + self.beton_grade = beton_grade + self.mix_id = mix_id + self.timestamp = timestamp or datetime.now() diff --git a/services/__init__.py b/services/__init__.py new file mode 100644 index 0000000..dc69dbb --- /dev/null +++ b/services/__init__.py @@ -0,0 +1,5 @@ +"""服务包""" +from .task_service import TaskService +from .monitoring_service import MonitoringService + +__all__ = ['TaskService', 'MonitoringService'] diff --git a/services/__pycache__/__init__.cpython-39.pyc b/services/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..603d984 Binary files /dev/null and b/services/__pycache__/__init__.cpython-39.pyc differ diff --git a/services/__pycache__/monitoring_service.cpython-39.pyc b/services/__pycache__/monitoring_service.cpython-39.pyc new file mode 100644 index 0000000..ad7892c Binary files /dev/null and b/services/__pycache__/monitoring_service.cpython-39.pyc differ diff --git a/services/__pycache__/task_service.cpython-39.pyc b/services/__pycache__/task_service.cpython-39.pyc new file mode 100644 index 0000000..e5188da Binary files /dev/null and b/services/__pycache__/task_service.cpython-39.pyc differ diff --git a/services/monitoring_service.py b/services/monitoring_service.py new file mode 100644 index 0000000..248838a --- /dev/null +++ b/services/monitoring_service.py @@ -0,0 +1,228 @@ + +"""监控服务""" +import time +import threading +from datetime import datetime +from database.access_db import AccessDB +from database.sql_server import SQLServerDB +from config.settings import ACCESS_DB_PATH, ACCESS_DB_PASSWORD, MONITOR_INTERVAL +from tcp.server import TCPServer + +class MonitoringService: + def __init__(self, tcp_server): + self.tcp_server = tcp_server + self.task_flags = {} + self.monitored_tasks = set() + self.inserted_tasks = {} + self.tasks_lock = threading.Lock() + + def monitor_access_flag_changes(self): + """监控Access数据库中派发任务的Flag状态""" + print("开始监控Access数据库中派发任务的Flag状态") + + while True: + try: + # 每2秒检查一次 + time.sleep(MONITOR_INTERVAL) + + with self.tasks_lock: + # 如果没有需要监控的任务,跳过 + if not self.monitored_tasks: + continue + + # 创建需要监控的任务列表副本 + tasks_to_monitor = self.monitored_tasks.copy() + + # 检查SQL Server中任务是否还存在 + sql_db = SQLServerDB() + try: + existing_tasks_in_sql = sql_db.check_existing_tasks(list(tasks_to_monitor)) + finally: + sql_db.close() + + # 分离已删除和未删除的任务 + erp_ids_str = [str(erp_id) for erp_id in tasks_to_monitor] + 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删除的任务才需要在Access中查找 + if not deleted_from_sql_tasks: + continue + + # 查询Access数据库中已删除任务的状态 + access_db = AccessDB(ACCESS_DB_PATH, ACCESS_DB_PASSWORD) + try: + current_tasks = access_db.query_task_status(list(deleted_from_sql_tasks)) + finally: + access_db.close() + + # 处理任务状态变化 + self._process_task_status_changes(deleted_from_sql_tasks, current_tasks) + + except Exception as e: + print(f"监控Access数据库 Flag时发生错误: {e}") + import traceback + traceback.print_exc() + continue + + def _process_task_status_changes(self, deleted_from_sql_tasks, current_tasks): + """处理任务状态变化""" + # 检查每个已删除任务的状态变化 + for erp_id_str in deleted_from_sql_tasks: + erp_id = int(erp_id_str) + current_flag = current_tasks.get(erp_id_str, "") + previous_flag = self.task_flags.get(erp_id_str, "") + + # 添加调试信息 + print(f"检查任务 {erp_id} - 当前Flag: '{current_flag}', 之前Flag: '{previous_flag}'") + + # 如果状态发生变化 + if current_flag != previous_flag: + with self.tasks_lock: + artifact_id = self.inserted_tasks.get(erp_id, "Unknown") + print( + f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 的Flag值已更新: {previous_flag} -> {current_flag}") + self.task_flags[erp_id_str] = current_flag + + # 根据Flag值末尾的字母执行相应操作并更新自定义数据表状态 + self._handle_flag_status_change(erp_id, current_flag, artifact_id) + + # 检查是否有任务记录已被删除(不在查询结果中但仍在监控列表中) + # 这表示任务可能已完成或从系统中移除 + missing_tasks = set(deleted_from_sql_tasks) - set(current_tasks.keys()) + if missing_tasks: + self._handle_missing_tasks(missing_tasks) + + def _handle_flag_status_change(self, erp_id, current_flag, artifact_id): + """处理标志状态变化""" + if current_flag.endswith('d'): + self._handle_status_d(erp_id, artifact_id) + elif current_flag.endswith('w'): + self._handle_status_w(erp_id, artifact_id) + elif current_flag.endswith('n'): + self._handle_status_n(erp_id, artifact_id) + elif current_flag.endswith('p'): + self._handle_status_p(erp_id, artifact_id) + elif current_flag.endswith('x'): + self._handle_status_x(erp_id, artifact_id) + + def _handle_status_d(self, erp_id, artifact_id): + """处理状态'd' - 未进行生产""" + print(f"派发任务 ErpID {erp_id}: 未进行生产") + # 调用同事提供的状态更新函数 + try: + print(1) + # update_custom_table_status(erp_id, "未进行生产") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "未进行生产" + } + self.tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + def _handle_status_w(self, erp_id, artifact_id): + """处理状态'w' - 正在生产中""" + print(f"派发任务 ErpID {erp_id}: 正在生产中") + # 调用同事提供的状态更新函数 + try: + print(2) + # update_custom_table_status(erp_id, "正在生产中") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "正在生产中" + } + self.tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + def _handle_status_n(self, erp_id, artifact_id): + """处理状态'n' - 生产完毕""" + print(f"派发任务 ErpID {erp_id}: 生产完毕") + # 任务完成,可以从监控列表中移除 + with self.tasks_lock: + self.monitored_tasks.discard(erp_id) + print(f"派发任务 ErpID {erp_id} 已完成,停止监控") + # 调用同事提供的状态更新函数 + try: + print(3) + # update_custom_table_status(erp_id, "生产完毕") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "生产完毕" + } + self.tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + def _handle_status_p(self, erp_id, artifact_id): + """处理状态'p' - 生产中断""" + print(f"派发任务 ErpID {erp_id}: 生产中断") + # 任务中断,可以从监控列表中移除 + with self.tasks_lock: + self.monitored_tasks.discard(erp_id) + print(f"派发任务 ErpID {erp_id} 已中断,停止监控") + # 调用同事提供的状态更新函数 + try: + print(4) + # update_custom_table_status(erp_id, "生产中断") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "生产中断" + } + self.tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + def _handle_status_x(self, erp_id, artifact_id): + """处理状态'x' - 数据已接收""" + print(f"派发任务 ErpID {erp_id}: 数据已接收") + # 调用同事提供的状态更新函数 + try: + print(5) + # update_custom_table_status(erp_id, "数据已接收") + except Exception as e: + print(f"更新状态时出错: {e}") + + # 发送数据给TCP客户端(只发送erp_id和状态) + try: + status_data = { + "erp_id": erp_id, + "status": "数据已接收" + } + self.tcp_server.send_data(status_data) + except Exception as e: + print(f"发送状态数据给TCP客户端时出错: {e}") + + def _handle_missing_tasks(self, missing_tasks): + """处理缺失的任务""" + for erp_id_str in missing_tasks: + erp_id = int(erp_id_str) + with self.tasks_lock: + artifact_id = self.inserted_tasks.get(erp_id, "Unknown") + self.monitored_tasks.discard(erp_id) + self.inserted_tasks.pop(erp_id, None) + self.task_flags.pop(erp_id_str, None) + print(f"派发任务 ErpID {erp_id} (ArtifactID: {artifact_id}) 记录已从Access数据库中删除或完成") diff --git a/services/task_service.py b/services/task_service.py new file mode 100644 index 0000000..4e8770b --- /dev/null +++ b/services/task_service.py @@ -0,0 +1,303 @@ +"""任务处理服务""" +from datetime import datetime +from API.client import APIClient +from database.access_db import AccessDB +from database.sql_server import SQLServerDB +from config.settings import ACCESS_DB_PATH, ACCESS_DB_PASSWORD +from utils.helpers import get_f_block_positions + + +class TaskService: + def __init__(self): + self.api_client = APIClient() + self.half_volume = [0, 0] + self.task_before = None + self.artifact_timestamps = {} + + def process_not_pour_info(self): + """处理未浇筑信息""" + artifact_list = self.api_client.get_not_pour_info() + + if not artifact_list: + return [], [], [], self.half_volume + + # 处理F块信息 + f_blocks_info = self._process_f_blocks(artifact_list) + f_blocks = f_blocks_info["f_blocks"] + f_block_count = f_blocks_info["f_block_count"] + total_f_volume = f_blocks_info["total_f_volume"] + f_positions = f_blocks_info["f_positions"] + + # 处理当前任务 + current_task = self._process_current_task(artifact_list[0]) + + # 更新上一个任务信息 + self.task_before = { + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"] + } + + # 根据F块情况处理任务 + task_result = self._handle_tasks_by_f_blocks( + f_block_count, f_positions, current_task, + f_blocks, total_f_volume, artifact_list + ) + + return task_result + + def _process_f_blocks(self, artifact_list): + """处理F块相关信息""" + f_blocks = [artifact for artifact in artifact_list if artifact.get("BlockNumber") == "F"] + f_block_count = len(f_blocks) + total_f_volume = sum(artifact["BetonVolume"] for artifact in f_blocks) + f_positions = get_f_block_positions(artifact_list) + + return { + "f_blocks": f_blocks, + "f_block_count": f_block_count, + "total_f_volume": total_f_volume, + "f_positions": f_positions + } + + def _process_current_task(self, latest_artifact): + """处理当前任务信息""" + task_data = self.api_client.get_task_info(latest_artifact["BetonTaskID"]) + return { + "beton_task_id": latest_artifact["BetonTaskID"], + "beton_volume": latest_artifact["BetonVolume"], + "artifact_id": latest_artifact["ArtifactActionID"], + "block_number": latest_artifact.get("BlockNumber", ""), + "task_data": task_data + } + + def _handle_tasks_by_f_blocks(self, f_block_count, f_positions, current_task, + f_blocks, total_f_volume, artifact_list): + """根据F块数量和位置处理任务""" + # 多个F块情况 + if f_block_count > 2: + return self._handle_multiple_f_blocks(current_task, total_f_volume, artifact_list) + + # 两个F块情况 + elif f_block_count == 2: + return self._handle_two_f_blocks(f_positions, current_task, total_f_volume, artifact_list) + + # 一个F块情况 + elif f_block_count == 1: + return self._handle_single_f_block(f_positions, current_task, f_blocks, + total_f_volume, artifact_list) + + # 无F块情况 + elif f_block_count == 0: + return self._handle_no_f_blocks(current_task, artifact_list) + + else: + print("报警") + return [], [], [], self.half_volume + + def _handle_multiple_f_blocks(self, current_task, total_f_volume, artifact_list): + """处理多个F块的情况""" + adjusted_volume = total_f_volume - self.half_volume[0] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + self._append_additional_tasks(send_list, artifact_list, [0, 0]) + + # 更新时间戳 + self._update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, self.half_volume + + def _handle_two_f_blocks(self, f_positions, current_task, total_f_volume, artifact_list): + """处理两个F块的情况""" + if f_positions == [0, 1] and self.task_before.get("block_number") == "F": + adjusted_volume = 0 + block_number = "补方" + else: + adjusted_volume = total_f_volume - self.half_volume[0] + block_number = current_task["block_number"] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + volumes = [adjusted_volume, + artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0] if f_positions == [0, + 1] and self.task_before.get( + "block_number") == "F" else [0, 0] + self._append_additional_tasks(send_list, artifact_list, volumes) + + # 更新时间戳 + self._update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, self.half_volume + + def _handle_single_f_block(self, f_positions, current_task, f_blocks, total_f_volume, artifact_list): + """处理单个F块的情况""" + if f_positions == [2]: + f_volume = f_blocks[0].get("BetonVolume") if f_blocks else 0 + self.half_volume[0] = round(total_f_volume / 2, 2) + self.half_volume[1] = f_volume - self.half_volume[0] + adjusted_volume = current_task["beton_volume"] + self.half_volume[0] + elif f_positions == [1]: + adjusted_volume = current_task["beton_volume"] + self.half_volume[1] + elif f_positions == [0]: + adjusted_volume = 0 + else: + adjusted_volume = current_task["beton_volume"] + + block_number = "补方" if f_positions == [0] else current_task["block_number"] + + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": adjusted_volume, + "artifact_id": current_task["artifact_id"], + "block_number": block_number, + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + self._append_additional_tasks_for_single_f(send_list, artifact_list, f_positions) + + # 更新时间戳 + self._update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, self.half_volume + + def _handle_no_f_blocks(self, current_task, artifact_list): + """处理无F块的情况""" + tasks = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + }] + + send_list = [{ + "beton_task_id": current_task["beton_task_id"], + "beton_volume": current_task["beton_volume"], + "artifact_id": current_task["artifact_id"], + "block_number": current_task["block_number"], + "beton_grade": current_task["task_data"]["BetonGrade"], + "mix_id": current_task["task_data"]["MixID"], + "time": self.artifact_timestamps.get(current_task["artifact_id"], datetime.now()) + }] + + # 处理后续任务 + self._append_additional_tasks(send_list, artifact_list, + [artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0, + artifact_list[2]["BetonVolume"] if len(artifact_list) > 2 else 0]) + + # 更新时间戳 + self._update_artifact_timestamps(send_list) + + return tasks, artifact_list, send_list, self.half_volume + + def _append_additional_tasks(self, send_list, artifact_list, volumes): + """添加额外的任务到发送列表""" + # 安全获取后续任务 + second_task = artifact_list[1] if len(artifact_list) > 1 else None + third_task = artifact_list[2] if len(artifact_list) > 2 else None + + if second_task: + task_data_second = self.api_client.get_task_info(second_task["BetonTaskID"]) + send_list.append({ + "beton_task_id": second_task["BetonTaskID"], + "beton_volume": volumes[0], + "artifact_id": second_task["ArtifactActionID"], + "block_number": second_task["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": self.artifact_timestamps.get(second_task["ArtifactActionID"], datetime.now()) + }) + + if third_task: + task_data_third = self.api_client.get_task_info(third_task["BetonTaskID"]) + send_list.append({ + "beton_task_id": third_task["BetonTaskID"], + "beton_volume": volumes[1], + "artifact_id": third_task["ArtifactActionID"], + "block_number": third_task["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": self.artifact_timestamps.get(third_task["ArtifactActionID"], datetime.now()) + }) + + def _append_additional_tasks_for_single_f(self, send_list, artifact_list, f_positions): + """为单个F块情况添加额外任务""" + second_task = artifact_list[1] if len(artifact_list) > 1 else None + third_task = artifact_list[2] if len(artifact_list) > 2 else None + + if second_task: + task_data_second = self.api_client.get_task_info(second_task["BetonTaskID"]) + volume = (third_task["BetonVolume"] if third_task else 0) if f_positions != [2] else ( + second_task["BetonVolume"] + self.half_volume[1]) + send_list.append({ + "beton_task_id": second_task["BetonTaskID"], + "beton_volume": volume, + "artifact_id": second_task["ArtifactActionID"], + "block_number": second_task["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": self.artifact_timestamps.get(second_task["ArtifactActionID"], datetime.now()) + }) + + if third_task: + task_data_third = self.api_client.get_task_info(third_task["BetonTaskID"]) + volume = third_task["BetonVolume"] if f_positions in [[1], [0]] else 0 + send_list.append({ + "beton_task_id": third_task["BetonTaskID"], + "beton_volume": volume, + "artifact_id": third_task["ArtifactActionID"], + "block_number": third_task["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": self.artifact_timestamps.get(third_task["ArtifactActionID"], datetime.now()) + }) + + def _update_artifact_timestamps(self, send_list): + """更新artifact时间戳""" + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in self.artifact_timestamps: + self.artifact_timestamps[artifact_id] = datetime.now() diff --git a/tcp/__init__.py b/tcp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tcp/__pycache__/__init__.cpython-39.pyc b/tcp/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..0163450 Binary files /dev/null and b/tcp/__pycache__/__init__.cpython-39.pyc differ diff --git a/tcp/__pycache__/server.cpython-39.pyc b/tcp/__pycache__/server.cpython-39.pyc new file mode 100644 index 0000000..a6e0632 Binary files /dev/null and b/tcp/__pycache__/server.cpython-39.pyc differ diff --git a/TCPServer.py b/tcp/server.py similarity index 95% rename from TCPServer.py rename to tcp/server.py index cd3ac9d..91643ff 100644 --- a/TCPServer.py +++ b/tcp/server.py @@ -2,8 +2,7 @@ import socket import json import threading import time -from datetime import datetime -import os + class TCPServer: @@ -109,16 +108,16 @@ class TCPServer: print(f"收到异常生产通知 - 时间: {timestamp}, ERP ID: {erp_id}") # 调用update_custom_table_status更新数据库状态 try: - # update_custom_table_status(erp_id, "异常生产") + update_custom_table_status(erp_id, "异常生产") print(f"数据库状态已更新为: 异常生产 (ERP ID: {erp_id})") except Exception as e: print(f"更新数据库状态时出错: {e}") - elif cmd == "interrupt_error": + elif cmd == "cancel_feed": print(f"收到中断生产通知 - 时间: {timestamp}, ERP ID: {erp_id}") # 调用update_custom_table_status更新数据库状态 try: - # update_custom_table_status(erp_id, "中断生产") - print(f"数据库状态已更新为: 中断生产 (ERP ID: {erp_id})") + update_custom_table_status(erp_id, "取消生产") + print(f"数据库状态已更新为: 取消生产 (ERP ID: {erp_id})") except Exception as e: print(f"更新数据库状态时出错: {e}") else: diff --git a/temp.py b/temp.py new file mode 100644 index 0000000..2214966 --- /dev/null +++ b/temp.py @@ -0,0 +1,432 @@ +def get_all_not_pour_info(app_id): # 添加这一行声明 + global task_before, half_volume, artifact_timestamps + 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"] + send_list = [] + tasks = [] + + if not artifact_list: + return tasks + if task_before is not None: + # 这里可以处理上一条任务的逻辑 + print(f"上一条任务: {task_before}") + # 记录F块位置 + f_positions = get_f_block_positions(artifact_list) + # 统计F块数量和总方量 + f_blocks = [artifact for artifact in artifact_list if artifact.get("BlockNumber") == "F"] + f_block_count = len(f_blocks) + total_f_volume = sum(artifact["BetonVolume"] for artifact in f_blocks) + + # 处理最上面一条 + latest_artifact = artifact_list[0] + beton_task_id = latest_artifact["BetonTaskID"] + beton_volume = latest_artifact["BetonVolume"] + artifact_id = latest_artifact["ArtifactActionID"] + block_number = latest_artifact.get("BlockNumber", "") + + task_before = { + "beton_task_id": latest_artifact["BetonTaskID"], + "beton_volume": latest_artifact["BetonVolume"], + "artifact_id": latest_artifact["ArtifactActionID"], + "block_number": latest_artifact.get("BlockNumber", "") + } + task_data = get_task_info(app_id, beton_task_id) + if f_block_count == 1 and f_positions == [2]: + f_volume = f_blocks.get("BetonVolume") + half_volume[0] = round(total_f_volume / 2, 2) + half_volume[1] = f_volume - half_volume[0] + # 如果有多个F块,先派当前任务,再创建补方任务 + if f_block_count > 2: + adjusted_volume = total_f_volume - half_volume[0] + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": 0, + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": 0, + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 2 and f_positions == [0, 1] and task_before.block_number == "F": + adjusted_volume = 0 + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": "补方", + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": adjusted_volume, + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 2 and f_positions == [1, 2]: + adjusted_volume = total_f_volume - half_volume[0] + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": beton_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": beton_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": adjusted_volume, + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": 0, + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 2 and f_positions == [0, 1] and task_before.block_number != "F": + adjusted_volume = total_f_volume - half_volume[0] + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": 0, + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 1 and f_positions == [2]: + adjusted_volume = beton_volume + half_volume[0] + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": beton_volume + half_volume[1], + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 1 and f_positions == [1]: + adjusted_volume = beton_volume + half_volume[1] + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + elif f_block_count == 1 and f_positions == [0]: + adjusted_volume = 0 + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": "补方", + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + elif f_block_count == 0: + adjusted_volume = beton_volume + tasks.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + }) + send_list.append({ + "beton_task_id": beton_task_id, + "beton_volume": adjusted_volume, + "artifact_id": artifact_id, + "block_number": block_number, + "beton_grade": task_data["BetonGrade"], + "mix_id": task_data["MixID"], + "time": artifact_timestamps.get(artifact_id, datetime.now()) + }) + dispatch_list_second = artifact_list[1] + task_data_second = get_task_info(app_id, dispatch_list_second["BetonTaskID"]) + dispatch_list_third = artifact_list[2] + task_data_third = get_task_info(app_id, dispatch_list_third["BetonTaskID"]) + send_list.append({ + "beton_task_id": dispatch_list_second["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_second["ArtifactActionID"], + "block_number": dispatch_list_second["BlockNumber"], + "beton_grade": task_data_second["BetonGrade"], + "mix_id": task_data_second["MixID"], + "time": artifact_timestamps.get(dispatch_list_second["ArtifactActionID"], datetime.now()) + }) + send_list.append({ + "beton_task_id": dispatch_list_third["BetonTaskID"], + "beton_volume": dispatch_list_third["BetonVolume"], + "artifact_id": dispatch_list_third["ArtifactActionID"], + "block_number": dispatch_list_third["BlockNumber"], + "beton_grade": task_data_third["BetonGrade"], + "mix_id": task_data_third["MixID"], + "time": artifact_timestamps.get(dispatch_list_third["ArtifactActionID"], datetime.now()) + }) + # 更新新出现的 artifact_id 的时间戳 + current_artifact_ids = {item["artifact_id"] for item in send_list} + for artifact_id in current_artifact_ids: + if artifact_id not in artifact_timestamps: + artifact_timestamps[artifact_id] = datetime.now() + return tasks, artifact_list, send_list, half_volume + + else: + print("报警") + + raise Exception("获取未浇筑信息失败") + + +{ + "ArtifactID": "QR1B32000153AD", + "ArtifactActionID": 346482967298128, + "ArtifactIDVice1": "Q00001AD", + "ProduceRingNumber": 1, + "MouldCode": "SHR2B3-9", + "SkeletonID": "QR1B2000048A", + "RingTypeCode": "R22", + "SizeSpecification": "6900*1500", + "BuriedDepth": "中埋", + "BlockNumber": "F", + "HoleRingMarking": "否", + "GroutingPipeMarking": "否", + "PolypropyleneFiberMarking": "否", + "BetonVolume": 0.55, + "BetonTaskID": "20251020-01" +}, \ No newline at end of file diff --git a/test.py b/test.py deleted file mode 100644 index 3861ab0..0000000 --- a/test.py +++ /dev/null @@ -1,5 +0,0 @@ -import pyodbc -print("系统中可用的ODBC驱动程序:") -for driver in pyodbc.drivers(): - if "Access" in driver or "Excel" in driver: - print(f" {driver}") diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/__pycache__/__init__.cpython-39.pyc b/utils/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000..a0ca318 Binary files /dev/null and b/utils/__pycache__/__init__.cpython-39.pyc differ diff --git a/utils/__pycache__/helpers.cpython-39.pyc b/utils/__pycache__/helpers.cpython-39.pyc new file mode 100644 index 0000000..dc045d5 Binary files /dev/null and b/utils/__pycache__/helpers.cpython-39.pyc differ diff --git a/utils/helpers.py b/utils/helpers.py new file mode 100644 index 0000000..6cba2f8 --- /dev/null +++ b/utils/helpers.py @@ -0,0 +1,43 @@ +"""工具函数模块""" + + +def get_f_block_positions(artifact_list): + """获取artifact_list中F块的位置""" + positions = [] + for i, artifact in enumerate(artifact_list): + if artifact.get("BlockNumber") == "F": + positions.append(i) + return positions + + +def cleanup_old_timestamps(artifact_timestamps, current_artifact_ids=None, max_age_hours=24): + """ + 清理过期的时间戳记录 + + Args: + artifact_timestamps: 时间戳字典 + current_artifact_ids: 当前活跃的artifact_id集合,可选 + max_age_hours: 时间戳最大保留时间(小时),默认24小时 + """ + from datetime import datetime + + current_time = datetime.now() + expired_ids = [] + + # 遍历所有存储的时间戳记录 + for artifact_id, timestamp in artifact_timestamps.items(): + # 如果提供了当前活跃ID列表,且该ID不在当前活跃列表中,则检查是否过期 + if current_artifact_ids is None or artifact_id not in current_artifact_ids: + age = current_time - timestamp + # 如果超过最大保留时间,则标记为过期 + if age.total_seconds() > max_age_hours * 3600: + expired_ids.append(artifact_id) + + # 删除过期的时间戳记录 + for artifact_id in expired_ids: + del artifact_timestamps[artifact_id] + + if expired_ids: + print(f"清理了 {len(expired_ids)} 个过期的时间戳记录: {expired_ids}") + + return len(expired_ids) diff --git a/zjsh_ui_sysytem b/zjsh_ui_sysytem index 30d00b8..fe751e8 160000 --- a/zjsh_ui_sysytem +++ b/zjsh_ui_sysytem @@ -1 +1 @@ -Subproject commit 30d00b8aef550efa6a06e69a64c24ab6b021e5c2 +Subproject commit fe751e8dd209b7a4bb8ac88b27a7291d347e20b9