提交
This commit is contained in:
0
app/blueprints/remote_data/__init__.py
Normal file
0
app/blueprints/remote_data/__init__.py
Normal file
539
app/blueprints/remote_data/rotutes.py
Normal file
539
app/blueprints/remote_data/rotutes.py
Normal file
@@ -0,0 +1,539 @@
|
||||
from datetime import datetime
|
||||
import re
|
||||
from flask import Blueprint, current_app, json, request, jsonify
|
||||
from flask_jwt_extended import jwt_required
|
||||
import requests
|
||||
from sqlalchemy import and_, func
|
||||
from app import db
|
||||
from app.models import BagFile, Fst
|
||||
from app.utils.fst_tree import build_tree
|
||||
|
||||
|
||||
remote_bp = Blueprint("remote", __name__)
|
||||
|
||||
|
||||
def extract_datetime_from_filename(bag_filename):
|
||||
"""
|
||||
从文件名中提取日期和时间。
|
||||
返回包含年月日时分秒的字符串、datetime对象以及视频URL。
|
||||
"""
|
||||
match = re.search(r"_(\d{8})-(\d{6})_", bag_filename)
|
||||
if not match:
|
||||
raise ValueError("文件名格式错误,无法提取时间信息")
|
||||
date_part, time_part = match.groups()
|
||||
|
||||
# 提取年月日时分秒各部分
|
||||
year = date_part[:4]
|
||||
month = date_part[4:6]
|
||||
day = date_part[6:8]
|
||||
hour = time_part[:2]
|
||||
minute = time_part[2:4]
|
||||
second = time_part[4:6]
|
||||
|
||||
# 年月日时分秒整合到一个变量(字符串格式)
|
||||
datetime_full = f"{year}-{month}-{day} {hour}:{minute}:{second}"
|
||||
|
||||
# 原有视频路径相关逻辑保持不变
|
||||
bag_filename = bag_filename.replace(".bag", "")
|
||||
video_final_path = f"{bag_filename}- Wide.mp4"
|
||||
video_cos = f"momenta/videos/{year}/{month}/{day}/{video_final_path}"
|
||||
video_url = (
|
||||
"https://data-miningc01-1318950322.cos.ap-shanghai-adc.myqcloud.com/"
|
||||
+ video_cos
|
||||
)
|
||||
|
||||
# 返回整合后的完整日期时间字符串、datetime对象和视频URL
|
||||
return datetime_full, video_url
|
||||
|
||||
|
||||
def get_level1_labels(root_data, target_level1_id, use_label=False):
|
||||
"""
|
||||
收集特定一级标签及其所有子标签的id(或label)为扁平数组
|
||||
:param root_data: 原始数据(字典或JSON字符串)
|
||||
:param target_level1_id: 目标一级标签的id
|
||||
:param use_label: 若为True则返回label,否则返回id(默认False)
|
||||
:return: 扁平标签数组(如未找到目标则返回空数组)
|
||||
"""
|
||||
# 确保root_data是字典
|
||||
if isinstance(root_data, str):
|
||||
try:
|
||||
root_data = json.loads(root_data)
|
||||
except json.JSONDecodeError:
|
||||
raise ValueError("root_data无法解析为JSON")
|
||||
if not isinstance(root_data, dict):
|
||||
raise TypeError("root_data必须是字典或JSON字符串")
|
||||
|
||||
result = []
|
||||
key = "label" if use_label else "id" # 选择使用label还是id
|
||||
|
||||
def recursive_collect(node):
|
||||
"""递归收集节点的标签(id或label)"""
|
||||
if not isinstance(node, dict) or key not in node:
|
||||
return
|
||||
# 只添加当前节点的标签(不保留其他字段)
|
||||
result.append(node[key])
|
||||
# 递归处理子节点
|
||||
for child in node.get("children", []):
|
||||
recursive_collect(child)
|
||||
|
||||
# 查找目标一级标签
|
||||
target_node = None
|
||||
for node in root_data.get("children", []):
|
||||
if (
|
||||
isinstance(node, dict)
|
||||
and node.get("level") == 1
|
||||
and node.get("id") == target_level1_id
|
||||
):
|
||||
target_node = node
|
||||
break
|
||||
|
||||
# 收集目标节点及其所有子标签
|
||||
if target_node:
|
||||
recursive_collect(target_node)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@remote_bp.route("/fstmenu", methods=["GET"])
|
||||
def fstmenu():
|
||||
# pass
|
||||
"""
|
||||
返回值:
|
||||
{
|
||||
path: string
|
||||
name: string
|
||||
title: string
|
||||
component: string
|
||||
children?: BackendRoute[]
|
||||
}
|
||||
|
||||
"""
|
||||
level1_tags = Fst.query.filter(Fst.level == 1).all()
|
||||
# result = [
|
||||
# {"id": tag.id, "name": tag.name, "level": tag.level} for tag in level1_tags
|
||||
# ]
|
||||
result = [
|
||||
{
|
||||
"path": tag.name,
|
||||
"name": tag.name,
|
||||
"title": tag.name,
|
||||
"component": "",
|
||||
}
|
||||
for tag in level1_tags
|
||||
]
|
||||
return jsonify(result)
|
||||
|
||||
|
||||
@remote_bp.route("/fstmenu1", methods=["GET"])
|
||||
def fstmenu1():
|
||||
# pass
|
||||
"""
|
||||
返回值:
|
||||
{
|
||||
path: string
|
||||
name: string
|
||||
title: string
|
||||
component: string
|
||||
children?: BackendRoute[]
|
||||
}
|
||||
|
||||
"""
|
||||
API_URL = "http://10.0.240.4:5232/api/fst/print_tree"
|
||||
TIMEOUT = 10 # 超时时间(秒)
|
||||
|
||||
try:
|
||||
response = requests.get(url=API_URL, timeout=TIMEOUT)
|
||||
# 3. 验证HTTP响应状态
|
||||
response.raise_for_status()
|
||||
level1_results = []
|
||||
# 遍历最外层的 children 列表(level=0 的子节点即 level=1)
|
||||
for node in response.json()[0]["children"]:
|
||||
# 二次验证 level 是否为 1(避免结构异常)
|
||||
if node.get("level") == 1:
|
||||
level1_results.append(
|
||||
{
|
||||
"path": node["id"],
|
||||
"name": node["label"],
|
||||
"title": node["label"],
|
||||
"component": "",
|
||||
}
|
||||
)
|
||||
|
||||
for node_park in response.json()[1]["children"]:
|
||||
# 二次验证 level 是否为 1(避免结构异常)
|
||||
if node_park.get("level") == 1:
|
||||
level1_results.append(
|
||||
{
|
||||
"path": node_park["id"],
|
||||
"name": node_park["label"],
|
||||
"title": node_park["label"],
|
||||
"component": "",
|
||||
}
|
||||
)
|
||||
return jsonify(level1_results)
|
||||
|
||||
except Exception as e:
|
||||
# 其他未捕获异常
|
||||
return jsonify({"success": False, "message": f"服务器处理错误:{str(e)}"})
|
||||
|
||||
|
||||
# 根据fst标签返回bag信息----一级标签的所有
|
||||
@remote_bp.route("/remote-baglist1", methods=["POST"])
|
||||
def query_bag_file_by_fst():
|
||||
try:
|
||||
# 1. 解析核心请求参数(仅保留:分页参数 + Fst 1-4级标签)
|
||||
params = request.get_json() or {}
|
||||
print(f"【请求参数】原始参数: {params}")
|
||||
|
||||
# 分页参数(默认第1页,每页20条)
|
||||
page = params.get("page", 1)
|
||||
per_page = params.get("per_page", 20)
|
||||
# Fst 标签参数(1-4级标签,字符串格式ID)
|
||||
level1_tag = params.get("level1_tag", "").strip()
|
||||
level2_tag = params.get("level2_tag", "").strip()
|
||||
level3_tag = params.get("level3_tag", "").strip()
|
||||
level4_tag = params.get("level4_tag", "").strip()
|
||||
|
||||
# 2. 构建基础查询
|
||||
query = BagFile.query
|
||||
|
||||
# 3. 核心过滤:仅保留 Fst 标签筛选条件
|
||||
conditions = []
|
||||
|
||||
# 一级标签过滤(转换为整数ID匹配)
|
||||
if level1_tag:
|
||||
try:
|
||||
conditions.append(BagFile.level1_tag_id == int(level1_tag))
|
||||
except ValueError:
|
||||
print(f"【过滤警告】一级标签ID格式错误: {level1_tag}")
|
||||
# 二级标签过滤
|
||||
if level2_tag:
|
||||
try:
|
||||
conditions.append(BagFile.level2_tag_id == int(level2_tag))
|
||||
except ValueError:
|
||||
print(f"【过滤警告】二级标签ID格式错误: {level2_tag}")
|
||||
# 三级标签过滤
|
||||
if level3_tag:
|
||||
try:
|
||||
conditions.append(BagFile.level3_tag_id == int(level3_tag))
|
||||
except ValueError:
|
||||
print(f"【过滤警告】三级标签ID格式错误: {level3_tag}")
|
||||
# 四级标签过滤
|
||||
if level4_tag:
|
||||
try:
|
||||
conditions.append(BagFile.level4_tag_id == int(level4_tag))
|
||||
except ValueError:
|
||||
print(f"【过滤警告】四级标签ID格式错误: {level4_tag}")
|
||||
|
||||
# 应用标签过滤条件
|
||||
if conditions:
|
||||
query = query.filter(and_(*conditions))
|
||||
|
||||
# 4. 核心排序:按 bag_update_time 降序(最新更新优先)
|
||||
query = query.order_by(BagFile.bag_update_time.desc())
|
||||
|
||||
# 5. 分页查询(页码超出时返回空列表,不报错)
|
||||
pagination = query.paginate(page=page, per_page=per_page, error_out=False)
|
||||
total_items = pagination.total # 总数据条数
|
||||
total_pages = pagination.pages # 总页数
|
||||
|
||||
# 6. 数据序列化(仅保留核心字段,包含 Fst 标签信息)
|
||||
bag_files = []
|
||||
for bag in pagination.items:
|
||||
# 拼接 Fst 标签“中文+英文”名称(提升可读性)
|
||||
level1_name = f"{bag.level1_tag.name}" if bag.level1_tag else None
|
||||
level2_name = f"{bag.level2_tag.name}" if bag.level2_tag else None
|
||||
level3_name = f"{bag.level3_tag.name}" if bag.level3_tag else None
|
||||
level4_name = f"{bag.level4_tag.name}" if bag.level4_tag else None
|
||||
|
||||
bag_files.append(
|
||||
{
|
||||
"id": bag.id,
|
||||
"file_name": bag.file_name, # BAG文件名
|
||||
"capture_datetime": (
|
||||
bag.capture_datetime.isoformat()
|
||||
if bag.capture_datetime
|
||||
else None
|
||||
), # 采集时间
|
||||
"bag_update_time": (
|
||||
bag.bag_update_time.isoformat() if bag.bag_update_time else None
|
||||
), # 排序依据字段
|
||||
# Fst 标签核心信息
|
||||
"level1_tag_id": bag.level1_tag_id,
|
||||
"level1_tag_name": level1_name,
|
||||
"level2_tag_id": bag.level2_tag_id,
|
||||
"level2_tag_name": level2_name,
|
||||
"level3_tag_id": bag.level3_tag_id,
|
||||
"level3_tag_name": level3_name,
|
||||
"level4_tag_id": bag.level4_tag_id,
|
||||
"level4_tag_name": level4_name,
|
||||
# 基础状态字段(按需保留,非核心可删除)
|
||||
"status": bag.status.name if bag.status else None,
|
||||
"bag_status": bag.bag_status,
|
||||
"comment": bag.comment1,
|
||||
"front_starttime": bag.front_start_sec,
|
||||
"front_endtime": bag.front_end_sec,
|
||||
"case_type": "简单场景" if bag.case_type == 1 else "复杂场景",
|
||||
"highway": "高速" if bag.high_speed == 1 else None,
|
||||
"city": "城区" if bag.urban == 1 else None,
|
||||
"driving": "parking" if bag.urban else "driving",
|
||||
"video_url": bag.video_url,
|
||||
}
|
||||
)
|
||||
|
||||
# 7. 返回精简响应
|
||||
return jsonify(
|
||||
{
|
||||
"code": 200,
|
||||
"data": bag_files,
|
||||
"total": total_items,
|
||||
"page": page,
|
||||
"pages": total_pages,
|
||||
"message": "根据 Fst 标签查询成功",
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
# 异常捕获与响应
|
||||
error_msg = f"查询出错:{str(e)}"
|
||||
print(f"【接口异常】{error_msg}")
|
||||
return (
|
||||
jsonify(
|
||||
{
|
||||
"code": 500,
|
||||
"data": [],
|
||||
"total": 0,
|
||||
"page": page if "page" in locals() else 1,
|
||||
"pages": 0,
|
||||
"message": error_msg,
|
||||
}
|
||||
),
|
||||
500,
|
||||
)
|
||||
|
||||
|
||||
@remote_bp.route("/remote-baglist", methods=["POST"])
|
||||
def query_bag_file_by_fst1():
|
||||
# 1. 解析核心请求参数(仅保留:分页参数 + Fst 1-4级标签)
|
||||
params = request.get_json() or {}
|
||||
print(f"【请求参数】原始参数: {params}")
|
||||
|
||||
# 分页参数(默认第1页,每页20条)
|
||||
page = params.get("page", 1)
|
||||
per_page = params.get("per_page", 20)
|
||||
# Fst 标签参数(1-4级标签,字符串格式ID)
|
||||
fst_tag_list = params.get("fst_tag", "")
|
||||
print(f"【请求参数】Fst 标签列表: {fst_tag_list}")
|
||||
|
||||
# 获取过滤的参数
|
||||
filter_fst = params.get("filter_fst", [])
|
||||
|
||||
# 把请求到的数据进行处理
|
||||
API_LEVEL1_URL = "http://10.0.240.4:5232/api/fst/print_tree"
|
||||
API_NODES_URL = "http://10.0.240.4:5232/api/fst/bags/nodes"
|
||||
|
||||
API_OTHER_INFO_URL = "http://10.0.240.4:5232/api/bags/fst/nodes"
|
||||
TIMEOUT = 10 # 超时时间(秒)
|
||||
|
||||
try:
|
||||
# 如果filter_fst为空,说明为一级标签
|
||||
if len(filter_fst) == 0:
|
||||
response = requests.get(url=API_LEVEL1_URL, timeout=TIMEOUT)
|
||||
# print(123,response.json())
|
||||
# 3. 验证HTTP响应状态
|
||||
response.raise_for_status()
|
||||
# 遍历最外层的 children 列表(level=0 的子节点即 level=1)
|
||||
driving_tree = response.json()[0]
|
||||
park_tree = response.json()[1]
|
||||
# 获取所有的一级标签的子标签,组成一个新的列表
|
||||
driving_fst_list = get_level1_labels(driving_tree, fst_tag_list)
|
||||
park_fst_list = get_level1_labels(park_tree, fst_tag_list)
|
||||
|
||||
if len(driving_fst_list)>0:
|
||||
fst_list=driving_fst_list
|
||||
|
||||
if len(park_fst_list)>0:
|
||||
fst_list=park_fst_list
|
||||
|
||||
# print(555,fst_list)
|
||||
filter_fst = fst_list
|
||||
|
||||
# 查询所有的标签
|
||||
query_params = {"page": page, "per_page": per_page} # 页码 # 每页条数
|
||||
# bag_files = []
|
||||
|
||||
if filter_fst:
|
||||
res_bags = requests.post(
|
||||
url=API_NODES_URL,
|
||||
params=query_params, # URL查询参数(自动拼接为 ?page=1&per_page=20)
|
||||
json=filter_fst, # JSON请求体(自动设置Content-Type头)
|
||||
timeout=TIMEOUT, # 超时时间(秒)
|
||||
)
|
||||
|
||||
# 对查询到结果,循环进行查询
|
||||
all_bag_list = res_bags.json()["items"]
|
||||
total_nums = res_bags.json()["total"]
|
||||
|
||||
# 获取所有的bag_name,组成一个列表
|
||||
bag_name_list = []
|
||||
for item in all_bag_list:
|
||||
bag_name = item.get("bag_name")
|
||||
if bag_name:
|
||||
bag_name_list.append(bag_name)
|
||||
|
||||
# 查询所有的bagname的列表数据,返回的数据是字典中对应的列表
|
||||
bag_other_info_list = requests.post(url=API_OTHER_INFO_URL, json=bag_name_list)
|
||||
|
||||
# 组装数据
|
||||
res_list=[]
|
||||
for row in all_bag_list:
|
||||
bag_name = row.get("bag_name")
|
||||
if bag_name:
|
||||
record={}
|
||||
record["file_name"]=bag_name
|
||||
record["level1_tag_name"] = fst_tag_list
|
||||
record["sub_tag_name"] = row.get('sts')
|
||||
|
||||
# 过滤值
|
||||
bag_other_detail=bag_other_info_list.json()[bag_name]
|
||||
if len(bag_other_detail)==0:
|
||||
record["comment"] = ""
|
||||
record["highway"] = ""
|
||||
record["city"] = ""
|
||||
record["driving"] = ""
|
||||
record["front_starttime"] = ""
|
||||
record["front_endtime"] = ""
|
||||
if len(bag_other_detail)==1:
|
||||
record["comment"] = bag_other_detail[0]["comments"]
|
||||
record["highway"] = ""
|
||||
record["city"] = ""
|
||||
record["driving"] = ""
|
||||
record["front_starttime"] = bag_other_detail[0]["start"]
|
||||
record["front_endtime"] = bag_other_detail[0]["end"]
|
||||
if len(bag_other_detail)>1:
|
||||
# 循环bag_other_detail的值,当row.get('sts')等于某项的name时。
|
||||
for info in bag_other_detail:
|
||||
if info['name']==row.get('sts'):
|
||||
record["comment"] = info['comments']
|
||||
record["highway"] = ""
|
||||
record["city"] = ""
|
||||
record["driving"] = ""
|
||||
record["front_starttime"] = info['start']
|
||||
record["front_endtime"] = info['end']
|
||||
else:
|
||||
record["comment"] = ""
|
||||
record["highway"] = ""
|
||||
record["city"] = ""
|
||||
record["driving"] = ""
|
||||
record["front_starttime"] = ""
|
||||
record["front_endtime"] = ""
|
||||
|
||||
datetime_full, video_url = extract_datetime_from_filename(bag_name)
|
||||
record["video_url"] = video_url
|
||||
record["capture_datetime"] = datetime_full
|
||||
|
||||
res_list.append(record)
|
||||
|
||||
# 7. 返回精简响应
|
||||
return jsonify(
|
||||
{
|
||||
"code": 200,
|
||||
"data": res_list,
|
||||
"total": total_nums,
|
||||
"page": page,
|
||||
"pages": page,
|
||||
"message": "根据 Fst 标签查询成功",
|
||||
}
|
||||
)
|
||||
|
||||
else:
|
||||
return (
|
||||
jsonify(
|
||||
{
|
||||
"code": 500,
|
||||
"data": [],
|
||||
"total": 0,
|
||||
"page": page if "page" in locals() else 1,
|
||||
"pages": 0,
|
||||
"message": "标签数据出错",
|
||||
}
|
||||
),
|
||||
500,
|
||||
)
|
||||
except Exception as e:
|
||||
# 异常捕获与响应
|
||||
error_msg = f"查询出错:{str(e)}"
|
||||
print(f"【接口异常】{error_msg}")
|
||||
return (
|
||||
jsonify(
|
||||
{
|
||||
"code": 500,
|
||||
"data": [],
|
||||
"total": 0,
|
||||
"page": page if "page" in locals() else 1,
|
||||
"pages": 0,
|
||||
"message": error_msg,
|
||||
}
|
||||
),
|
||||
500,
|
||||
)
|
||||
|
||||
|
||||
@remote_bp.route("/sub-fst", methods=["GET"])
|
||||
def get_sub_fst1():
|
||||
target_label = request.args.get("fst_id")
|
||||
|
||||
API_URL = "http://10.0.240.4:5232/api/fst/print_tree"
|
||||
TIMEOUT = 10 # 超时时间(秒)
|
||||
|
||||
try:
|
||||
response = requests.get(url=API_URL, timeout=TIMEOUT)
|
||||
# 3. 验证HTTP响应状态
|
||||
response.raise_for_status()
|
||||
# 遍历最外层的 children 列表(level=0 的子节点即 level=1)
|
||||
|
||||
result=[]
|
||||
for node in response.json()[0].get("children", []):
|
||||
if node.get("level") == 1 and node.get("label") == target_label:
|
||||
data = node.get("children", [])
|
||||
if data:
|
||||
result=data
|
||||
|
||||
for node_park in response.json()[1].get("children", []):
|
||||
if node_park.get("level") == 1 and node_park.get("label") == target_label:
|
||||
data_park = node_park.get("children", [])
|
||||
if data_park:
|
||||
result=data_park
|
||||
|
||||
return jsonify({"code": 200, "data": result}) # 返回该节点的children
|
||||
|
||||
|
||||
return (
|
||||
jsonify({"code": 404, "message": "Fst not found"}),
|
||||
404,
|
||||
) # 未找到匹配节点时返回None
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "message": f"服务器处理错误:{str(e)}"})
|
||||
|
||||
|
||||
@remote_bp.route("/all-fst", methods=["GET"])
|
||||
def get_all_fst1():
|
||||
type = request.args.get("type")
|
||||
|
||||
API_URL = "http://10.0.240.4:5232/api/fst/print_tree"
|
||||
TIMEOUT = 10 # 超时时间(秒)
|
||||
|
||||
try:
|
||||
response = requests.get(url=API_URL, timeout=TIMEOUT)
|
||||
# 3. 验证HTTP响应状态
|
||||
response.raise_for_status()
|
||||
if type == "driving":
|
||||
return jsonify({"code": 200, "data": response.json()[0]})
|
||||
|
||||
if type == "parking":
|
||||
return jsonify({"code": 200, "data": response.json()[1]})
|
||||
except Exception as e:
|
||||
return jsonify({"success": False, "message": f"服务器处理错误:{str(e)}"})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user