import requests import json import logging import socket from typing import Optional, Dict, Any import globals.global_variable as global_variable def send_tcp_command(command="StartMultiple", host="127.0.0.1", port=8888, timeout=10): """ 使用TCP协议发送命令到指定地址和端口 参数: command: 要发送的命令字符串(默认:"StartMultiple") host: 目标主机地址(默认:"127.0.0.1") port: 目标端口(默认:8888) timeout: 连接超时时间(秒,默认:10) 返回: 成功返回服务器响应(字符串),失败返回None """ # 创建TCP套接字 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: try: # 设置超时时间 sock.settimeout(timeout) # 连接到目标服务器 sock.connect((host, port)) logging.info(f"已成功连接到 {host}:{port}") # 发送命令(注意:需要根据服务器要求的编码格式发送,这里用UTF-8) sock.sendall(command.encode('utf-8')) logging.info(f"已发送命令: {command}") # 接收服务器响应(缓冲区大小1024字节,可根据实际情况调整) response = sock.recv(1024) if response: response_str = response.decode('utf-8') logging.info(f"收到响应: {response_str}") return response_str else: logging.info("未收到服务器响应") return None except ConnectionRefusedError: logging.info(f"连接被拒绝,请检查 {host}:{port} 是否开启服务") return None except socket.timeout: logging.info(f"连接超时({timeout}秒)") return None except Exception as e: logging.info(f"发送命令时发生错误: {str(e)}") return None def get_breakpoint_list(): """ 获取需要处理的断点列表 """ # 请求参数 params = { 'user_name': global_variable.get_username() } # 请求地址 url = "https://engineering.yuxindazhineng.com/index/index/get_name_all" try: # 发送GET请求 response = requests.get(url, params=params, timeout=30) # 检查请求是否成功 if response.status_code == 200: result = response.json() # 检查接口返回状态 if result.get('code') == 0: data = result.get('data', []) logging.info("成功获取断点列表,数据条数:", len(data)) # 打印断点信息 # for item in data: # logging.info(f"线路编码: {item.get('line_num')}, " # f"线路名称: {item.get('line_name')}, " # f"状态: {item.get('status')}, " # f"用户: {item.get('name')}") return data else: logging.info(f"接口返回错误: {result.get('code')}") return [{"id": 37, "user_name": "wangshun", "name": "wangshun", "line_num": "L193588", "line_name": "CDWZQ-2标-155号路基左线-461221-461570-155左-平原", "status": 3 }] else: logging.info(f"请求失败,状态码: {response.status_code}") return [] except requests.exceptions.RequestException as e: logging.info(f"请求异常: {e}") return [] except ValueError as e: logging.info(f"JSON解析错误: {e}") return [] def get_measurement_task(): """ 获取测量任务 返回: 如果有状态为1的数据返回任务信息,否则返回None """ try: url = "https://engineering.yuxindazhineng.com/index/index/getOne" # 获取用户名 user_name = global_variable.get_username() if not user_name: logging.error("未设置用户名,无法获取测量任务") return None # 构造请求参数 data = { "user_name": user_name } logging.info(f"请求参数: user_name={user_name}") response = requests.post(url, data=data, timeout=10) response.raise_for_status() data = response.json() logging.info(f"接口返回数据: {data}") if data.get('code') == 0 and data.get('data'): task_data = data['data'] if task_data.get('status') == 1: logging.info(f"获取到测量任务: {task_data}") return task_data else: logging.info("获取到的任务状态不为1,不执行测量") return None else: logging.warning("未获取到有效任务数据") return None except Exception as e: logging.error(f"获取测量任务失败: {str(e)}") return None def get_end_with_num(): """ 根据线路编码获取测量任务 返回: 如果有状态为1的数据返回任务信息,否则返回None """ try: url = "https://engineering.yuxindazhineng.com/index/index/getOne3" # 获取用户名 user_name = global_variable.get_username() line_num = global_variable.get_line_num() if not line_num: logging.error("未设置线路编码,无法获取测量任务") return None if not user_name: logging.error("未设置用户名,无法获取测量任务") return None # 构造请求参数 data = { "user_name": user_name, "line_num": line_num } # logging.info(f"请求参数: user_name={user_name}, line_num={line_num}") response = requests.post(url, data=data, timeout=10) response.raise_for_status() data = response.json() logging.info(f"接口返回数据: {data}") if data.get('code') == 0 and data.get('data'): task_data = data['data'] if task_data.get('status') == 3: logging.info(f"获取到测量任务: {task_data}") return task_data else: logging.info("获取到的任务状态不为3,不执行测量") return None else: # logging.warning("未获取到有效任务数据") return None except Exception as e: logging.error(f"获取测量任务失败: {str(e)}") return None def get_work_conditions_by_linecode(linecode: str) -> Optional[Dict[str, Dict]]: """ 通过线路编码获取工况信息 Args: linecode: 线路编码,如 "L118134" Returns: 返回字典,格式为 {point_id: {"sjName": "", "workinfoname": "", "work_type": ""}} 如果请求失败返回None """ url="http://www.yuxindazhineng.com:3002/api/comprehensive_data/get_settlement_by_linecode" max_retries = 3 # 最大重试次数 retry_count = 0 # 当前重试计数 while retry_count < max_retries: try: # 准备请求参数 payload = {"linecode": linecode} headers = { 'Content-Type': 'application/json', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' } logging.info(f"发送POST请求到: {url}") logging.info(f"请求参数: {payload}") # 发送POST请求 response = requests.post( url, json=payload, headers=headers, timeout=30 ) # 检查响应状态 if response.status_code != 200: logging.error(f"HTTP请求失败,状态码: {response.status_code}") retry_count += 1 if retry_count < max_retries: logging.info(f"准备重试... (剩余 {max_retries - retry_count} 次)") continue # 继续重试 # 解析响应数据 try: result = response.json() except json.JSONDecodeError as e: logging.error(f"JSON解析失败: {str(e)}") retry_count += 1 if retry_count < max_retries: logging.info(f"准备重试... (剩余 {max_retries - retry_count} 次)") continue # 继续重试 # 检查API返回码 if result.get('code') != 0: logging.error(f"API返回错误: {result.get('message', '未知错误')}") return None # 提取数据 data_list = result.get('data', []) if not data_list: logging.warning("未找到工况数据") return {} # 处理数据,提取所需字段 work_conditions = {} for item in data_list: point_id = item.get('aname') if point_id: work_conditions[point_id] = { "sjName": item.get('sjName', ''), "workinfoname": item.get('next_workinfo', ''), "work_type": item.get('work_type', '') } logging.info(f"成功提取 {len(work_conditions)} 个测点的工况信息") return work_conditions except requests.exceptions.RequestException as e: logging.error(f"网络请求异常: {str(e)}") retry_count += 1 if retry_count < max_retries: logging.info(f"准备重试... (剩余 {max_retries - retry_count} 次)") except json.JSONDecodeError as e: logging.error(f"JSON解析失败: {str(e)}") retry_count += 1 if retry_count < max_retries: logging.info(f"准备重试... (剩余 {max_retries - retry_count} 次)") except Exception as e: logging.error(f"获取工况信息时发生未知错误: {str(e)}") retry_count += 1 if retry_count < max_retries: logging.info(f"准备重试... (剩余 {max_retries - retry_count} 次)") # 达到最大重试次数仍失败 logging.error(f"已达到最大重试次数 ({max_retries} 次),请求失败") return None def get_user_max_variation(username: str) -> Optional[int]: """ 调用POST接口根据用户名获取用户的max_variation信息 Args: username: 目标用户名,如 "chzq02-02guoyu" Returns: 成功:返回用户的max_variation整数值 失败:返回None """ # 接口基础配置 api_url = "http://www.yuxindazhineng.com:3002/api/accounts/get" timeout = 30 # 超时时间(避免请求长时间阻塞) # 1. 准备请求参数与头部 # 接口要求的POST参数(JSON格式) payload = {"username": username} # 请求头部:指定JSON格式,模拟浏览器UA避免被接口拦截 headers = { "Content-Type": "application/json", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" } try: # 2. 发送POST请求 response = requests.post( url=api_url, json=payload, # 自动将字典转为JSON字符串,无需手动json.dumps() headers=headers, timeout=timeout ) # 3. 检查HTTP响应状态(200表示请求成功到达服务器) response.raise_for_status() # 若状态码非200(如404、500),直接抛出HTTPError logging.info(f"接口请求成功,HTTP状态码:{response.status_code}") # 4. 解析JSON响应(处理文档中提到的"网页解析失败"风险) try: response_data = response.json() except json.JSONDecodeError as e: logging.error(f"接口返回数据非JSON格式,解析失败:{str(e)}") logging.error(f"接口原始返回内容:{response.text[:500]}") # 打印前500字符便于排查 return None # 5. 检查接口业务逻辑是否成功(按需求中"code=0表示查询成功") if response_data.get("code") != 0: logging.error(f"接口查询失败,业务错误信息:{response_data.get('message', '未知错误')}") return None # 6. 验证返回数据结构并提取max_variation data_list = response_data.get("data", []) if not data_list: logging.warning(f"查询到用户名 {username},但未返回账号数据") return None # 检查第一条数据是否包含max_variation first_user = data_list[0] if "max_variation" not in first_user: logging.warning(f"用户 {username} 的返回数据中缺少 max_variation 字段") return None max_variation = first_user["max_variation"] logging.info(f"成功查询到用户 {username} 的 max_variation:{max_variation}") # 7. 直接返回max_variation的值 return max_variation # 处理请求过程中的异常(网络问题、超时等) except requests.exceptions.RequestException as e: logging.error(f"接口请求异常(网络/超时/服务器不可达):{str(e)}") # 若为连接错误,提示检查文档中提到的"不支持的网页类型"或域名有效性 if "ConnectionRefusedError" in str(e) or "Failed to establish a new connection" in str(e): logging.error(f"建议排查:1. 接口域名 {api_url} 是否可访问;2. 服务器是否正常运行;3. 端口3002是否开放") return None # 处理其他未知异常 except Exception as e: logging.error(f"获取用户 {username} 的 max_variation 时发生未知错误:{str(e)}") return None requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) # def get_line_info_and_save_global(user_name: str) -> bool: # """ # 调用get_name_all接口,提取status=3的line_num和line_name存入全局字典 # :param user_name: 接口请求参数,如"wangshun" # :return: 执行成功返回True,失败/异常返回False # """ # # 接口基础配置 # api_url = "https://engineering.yuxindazhineng.com/index/index/get_name_all" # request_params = {"user_name": user_name} # GET请求参数 # timeout = 10 # 请求超时时间(秒),避免卡进程 # try: # # 1. 发送GET请求 # response = requests.get( # url=api_url, # params=request_params, # GET参数用params传递,自动拼接到URL后,规范且防乱码 # timeout=timeout, # verify=False # 禁用SSL验证,适配HTTPS接口 # ) # # 2. 校验HTTP状态码(先确保请求本身成功) # if response.status_code != 200: # logging.error(f"接口请求失败,HTTP状态码异常:{response.status_code},响应内容:{response.text}") # return False # # 3. 解析JSON响应(接口返回是JSON格式,需解析为字典) # try: # response_data = response.json() # except Exception as e: # logging.error(f"接口返回内容非合法JSON,无法解析:{response.text},错误:{str(e)}") # return False # # 4. 校验业务状态码(接口约定:code=0成功,-1失败) # business_code = response_data.get("code") # if business_code == 0: # logging.info("接口业务请求成功,开始解析数据") # elif business_code == -1: # logging.error(f"接口业务请求失败,业务状态码code=-1,返回数据:{response_data}") # return False # else: # logging.warning(f"接口返回未知业务状态码:{business_code},请确认接口文档") # return False # # 5. 提取data字段,校验数据是否存在 # api_data_list = response_data.get("data") # if not api_data_list: # logging.warning("接口业务成功,但data字段为空或无数据") # return False # # 6. 校验data是否为列表类型 # if not isinstance(api_data_list, list): # logging.error(f"data字段不是列表类型,实际类型:{type(api_data_list)},内容:{api_data_list}") # return False # found_valid_data = False # # 7. 遍历列表,提取所有status=3的数据 # for item in api_data_list: # # 确保每个item是字典 # if not isinstance(item, dict): # logging.warning(f"列表中的元素不是字典类型,跳过:{item}") # continue # # 获取字段值 # data_status = item.get("status") # line_num = item.get("line_num") # line_name = item.get("line_name") # # 校验status是否为3,且目标字段非空 # if data_status == 3 and line_num and line_name: # # # 存入全局字典:key=line_num,value=line_name # # global_variable.GLOBAL_UPLOAD_BREAKPOINT_DICT[line_num] = line_name # # 存入全局字典:key=line_name,value=line_num # global_variable.get_upload_breakpoint_dict()[line_name] = line_num # print(f"当前全局字典数据上传线路字典数据:{global_variable.get_upload_breakpoint_dict()}") # # 如果line_name不在列表中,则添加 # if line_name not in global_variable.get_upload_breakpoint_list(): # global_variable.get_upload_breakpoint_list().append(line_name) # logging.info(f"找到status=3的线路信息:line_num={line_num}, line_name={line_name}") # found_valid_data = True # if found_valid_data: # logging.info(f"成功提取所有status=3的线路信息,当前全局字典数据:{global_variable.get_upload_breakpoint_dict()}") # return True # else: # logging.warning("data列表中未找到任何status=3且字段完整的线路信息") # return False # # 捕获所有请求相关异常(超时、连接失败、网络异常等) # except requests.exceptions.Timeout: # logging.error(f"调用get_name_all接口超时,超时时间:{timeout}秒,请求参数:{request_params}") # return False # except requests.exceptions.ConnectionError: # logging.error(f"调用get_name_all接口连接失败,检查网络或接口地址是否正确:{api_url}") # return False # except Exception as e: # logging.error(f"调用get_name_all接口时发生未知异常:{str(e)}", exc_info=True) # exc_info=True打印异常堆栈,方便排查 # return False def get_line_info_and_save_global(user_name: str) -> bool: """ 调用get_name_all接口,提取status=3的line_num和line_name存入全局字典 :param user_name: 接口请求参数,如"wangshun" :return: 执行成功返回True,失败/异常返回False """ # 接口基础配置 api_url = "https://engineering.yuxindazhineng.com/index/index/get_name_all" request_params = {"user_name": user_name} # GET请求参数 timeout = 10 # 请求超时时间(秒),避免卡进程 max_retries = 3 # 最大重试次数 retry_interval = 2 # 重试间隔(秒) for retry in range(max_retries): try: # 1. 发送GET请求 response = requests.get( url=api_url, params=request_params, # GET参数用params传递,自动拼接到URL后,规范且防乱码 timeout=timeout, verify=False # 禁用SSL验证,适配HTTPS接口 ) # 2. 校验HTTP状态码(先确保请求本身成功) if response.status_code != 200: logging.error(f"接口请求失败,HTTP状态码异常:{response.status_code},响应内容:{response.text}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False # 3. 解析JSON响应(接口返回是JSON格式,需解析为字典) try: response_data = response.json() except Exception as e: logging.error(f"接口返回内容非合法JSON,无法解析:{response.text},错误:{str(e)}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False # 4. 校验业务状态码(接口约定:code=0成功,-1失败) business_code = response_data.get("code") if business_code == 0: logging.info("接口业务请求成功,开始解析数据") elif business_code == -1: logging.error(f"接口业务请求失败,业务状态码code=-1,返回数据:{response_data}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False else: logging.warning(f"接口返回未知业务状态码:{business_code},请确认接口文档") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False # 5. 提取data字段,校验数据是否存在 api_data_list = response_data.get("data") if not api_data_list: logging.warning("接口业务成功,但data字段为空或无数据") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False # 6. 校验data是否为列表类型 if not isinstance(api_data_list, list): logging.error(f"data字段不是列表类型,实际类型:{type(api_data_list)},内容:{api_data_list}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False found_valid_data = False # 7. 遍历列表,提取所有status=3的数据 for item in api_data_list: # 确保每个item是字典 if not isinstance(item, dict): logging.warning(f"列表中的元素不是字典类型,跳过:{item}") continue # 获取字段值 data_status = item.get("status") line_num = item.get("line_num") line_name = item.get("line_name") # 校验status是否为3,且目标字段非空 if data_status == 3 and line_num and line_name: # # 存入全局字典:key=line_num,value=line_name # global_variable.GLOBAL_UPLOAD_BREAKPOINT_DICT[line_num] = line_name # 存入全局字典:key=line_name,value=line_num global_variable.get_upload_breakpoint_dict()[line_name] = line_num print(f"当前全局字典数据上传线路字典数据:{global_variable.get_upload_breakpoint_dict()}") # 如果line_name不在列表中,则添加 if line_name not in global_variable.get_upload_breakpoint_list(): global_variable.get_upload_breakpoint_list().append(line_name) logging.info(f"找到status=3的线路信息:line_num={line_num}, line_name={line_name}") found_valid_data = True if found_valid_data: logging.info(f"成功提取所有status=3的线路信息,当前全局字典数据:{global_variable.get_upload_breakpoint_dict()}") return True else: logging.warning("data列表中未找到任何status=3且字段完整的线路信息") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False # 捕获所有请求相关异常(超时、连接失败、网络异常等) except requests.exceptions.Timeout: logging.error(f"调用get_name_all接口超时,超时时间:{timeout}秒,请求参数:{request_params}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False except requests.exceptions.ConnectionError: logging.error(f"调用get_name_all接口连接失败,检查网络或接口地址是否正确:{api_url}") if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False except Exception as e: logging.error(f"调用get_name_all接口时发生未知异常:{str(e)}", exc_info=True) # exc_info=True打印异常堆栈,方便排查 if retry < max_retries - 1: logging.info(f"将在{retry_interval}秒后进行第{retry+2}次重试") time.sleep(retry_interval) continue return False def get_accounts_from_server(yh_id): """从服务器获取账户信息""" url = "http://www.yuxindazhineng.com:3002/api/accounts/get_uplaod_data" headers = { "Content-Type": "application/json" } data = { "yh_id": yh_id } try: print(f"🔍 查询服务器账户信息,用户ID: {yh_id}") response = requests.post(url, headers=headers, json=data, timeout=10) if response.status_code == 200: result = response.json() if result.get("code") == 0: print(f"✅ 查询成功,找到 {result.get('total', 0)} 个账户") return result.get("data", []) else: print(f"❌ 查询失败: {result.get('message', '未知错误')}") return [] else: print(f"❌ 服务器响应错误: {response.status_code}") return [] except requests.exceptions.RequestException as e: print(f"❌ 网络请求失败: {e}") return [] except json.JSONDecodeError as e: print(f"❌ JSON解析失败: {e}") return []