520 lines
19 KiB
Python
520 lines
19 KiB
Python
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.GLOBAL_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 filter_breakpoint_list_by_status(status_codes):
|
||
"""
|
||
根据状态码过滤断点列表,只保留line_name
|
||
|
||
Args:
|
||
status_codes: 状态码列表,如 [0, 1] 或 [0, 1, 2, 3]
|
||
|
||
Returns:
|
||
list: 包含line_name的列表
|
||
"""
|
||
data = get_breakpoint_list()
|
||
|
||
if not data:
|
||
logging.info("获取断点列表失败或列表为空")
|
||
return []
|
||
|
||
# 根据状态码过滤数据
|
||
if status_codes:
|
||
filtered_data = [item for item in data if item.get('status') in status_codes]
|
||
logging.info(f"过滤后的断点数量 (状态{status_codes}): {len(filtered_data)}")
|
||
|
||
# 按状态分组显示
|
||
for status in status_codes:
|
||
status_count = len([item for item in filtered_data if item.get('status') == status])
|
||
logging.info(f"状态{status}的断点数量: {status_count}")
|
||
else:
|
||
# 如果没有指定状态码,返回所有数据
|
||
filtered_data = data
|
||
logging.info("未指定状态码,返回所有数据")
|
||
return filtered_data
|
||
|
||
def get_measurement_task():
|
||
"""
|
||
获取测量任务
|
||
返回: 如果有状态为1的数据返回任务信息,否则返回None
|
||
"""
|
||
try:
|
||
url = "https://engineering.yuxindazhineng.com/index/index/getOne"
|
||
|
||
# 获取用户名
|
||
user_name = global_variable.GLOBAL_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.GLOBAL_USERNAME
|
||
line_num = global_variable.GLOBAL_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 change_breakpoint_status(user_name, line_num, status):
|
||
"""
|
||
修改断点状态
|
||
|
||
Args:
|
||
user_name: 登录账号名
|
||
line_num: 线路编码
|
||
status: 当前工作状态,0未开始 1操作中 2操作完成
|
||
|
||
Returns:
|
||
bool: 操作是否成功
|
||
"""
|
||
try:
|
||
url = "https://engineering.yuxindazhineng.com/index/index/change"
|
||
data = {
|
||
"user_name": user_name,
|
||
"line_num": line_num,
|
||
"status": status
|
||
}
|
||
|
||
response = requests.post(url, data=data, timeout=10)
|
||
result = response.json()
|
||
|
||
if result.get("code") == 0:
|
||
logging.info(f"修改断点状态成功: 线路{line_num} 状态{status} - {result.get('msg')}")
|
||
return True
|
||
else:
|
||
logging.error(f"修改断点状态失败: 线路{line_num} 状态{status} - {result.get('msg')}")
|
||
return False
|
||
|
||
except Exception as e:
|
||
logging.error(f"修改断点状态请求异常: {str(e)}")
|
||
return False
|
||
|
||
|
||
def get_one_addr(user_name):
|
||
"""
|
||
根据用户名获取一个地址信息
|
||
|
||
Args:
|
||
user_name (str): 登录用户名
|
||
|
||
Returns:
|
||
dict: API的原始响应数据
|
||
"""
|
||
# 请求地址
|
||
url = "https://engineering.yuxindazhineng.com/index/index/getOneAddr"
|
||
|
||
# 请求参数
|
||
data = {
|
||
"user_name": user_name
|
||
}
|
||
|
||
# 请求头
|
||
headers = {
|
||
'Content-Type': 'application/json'
|
||
}
|
||
|
||
try:
|
||
# 发送POST请求
|
||
response = requests.post(url,data=data,timeout=10)
|
||
|
||
# 检查请求是否成功
|
||
response.raise_for_status()
|
||
|
||
# 解析返回数据的地址
|
||
addr = response.json().get('data').get('addr')
|
||
if addr:
|
||
logging.info(f"获取到地址: {addr}")
|
||
else:
|
||
logging.warning("返回数据中未包含地址信息")
|
||
|
||
# 直接返回API的响应
|
||
return addr
|
||
|
||
except requests.exceptions.RequestException as e:
|
||
# 返回错误信息
|
||
return False
|
||
except json.JSONDecodeError as e:
|
||
return False
|
||
|
||
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('workinfoname', ''),
|
||
"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请求
|
||
logging.info(f"向接口 {api_url} 发送请求,查询用户名:{username}")
|
||
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
|
||
|
||
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 [] |