from collections import defaultdict from datetime import datetime, timedelta import json def process_incident_data_gen6(test_val): """ 处理事故数据,按照incident_name去重(移除原incident_time组合去重),移除idc_tickcount_ms排序,其他逻辑不变。 Args: test_val (list): 原始数据列表 Returns: dict: 格式化后的数据 """ # 1. 仅按照 incident_name 去重(核心修改点1:移除incident_time组合) unique_data_dict = {} for item in test_val: name = item.get("incident_name") # 仅判断incident_name是否存在,不再依赖incident_time if name: # 仅用incident_name作为去重键 key = name if key not in unique_data_dict: unique_data_dict[key] = item # 获取去重后的数据列表(核心修改点2:移除排序步骤) unique_data_list = list(unique_data_dict.values()) # 3. 提取指定字段(原逻辑完全保留,仅将遍历对象从sorted_data改为unique_data_list) processed_events_data = [] for index, item in enumerate(unique_data_list, 1): incident_time_str = item.get("incident_time") if not incident_time_str: continue try: # 解析新的时间格式 "2025-11-30 20:51:35.684000" # 先尝试直接解析完整格式 try: # 移除毫秒部分,只保留到秒 base_time_str = incident_time_str.split('.')[0] incident_datetime = datetime.strptime(base_time_str, "%Y-%m-%d %H:%M:%S") except ValueError: # 如果失败,尝试其他可能的格式 try: incident_datetime = datetime.fromisoformat(incident_time_str.replace('Z', '+00:00')) except: # 再次失败,使用当前时间 incident_datetime = datetime.now() # 格式化日期和时间 date_str_result = incident_datetime.strftime("%Y-%m-%d") time_str_result = incident_datetime.strftime("%H:%M:%S") except (ValueError, TypeError) as e: print(f"Warning: Failed to parse incident_time '{incident_time_str}': {e}") # 使用默认值 date_str_result = item.get("dt", "").split(' ')[0] if item.get("dt") else datetime.now().strftime("%Y-%m-%d") time_str_result = "00:00:00" # 创建新的字典 processed_item = { "id": index, "oneid": item.get("oneid", ""), "date": date_str_result, "time": time_str_result, "incident_name": item.get("incident_name", ""), "incident_description": "", } processed_events_data.append(processed_item) # 4. 构建最终返回的字典 total_count = len(processed_events_data) result = {"data": processed_events_data, "total": total_count} return result def aggregate_and_sort_incidents_gen6(raw_data): """ 简化版本:按(incident_time + incident_name)精确聚合 适用于同一事件的incident_time完全一致的情况 """ aggregate_dict = {} for item in raw_data: incident_time = item.get("incident_time", "1970-01-01 00:00:00.000") incident_name = item.get("incident_name", "unknown_incident") aggregate_key = (incident_time, incident_name) if aggregate_key not in aggregate_dict: aggregate_dict[aggregate_key] = { "base_info": { "oneid": item.get("oneid"), "incident_time": incident_time, "speed": item.get("speed"), "gps_heading": item.get("gps_heading"), "incident_name": incident_name, "latitude": item.get("latitude"), "longitude": item.get("longitude"), "odometer": item.get("odometer"), "sw_version": item.get("sw_version"), "carmodel": item.get("carmodel"), "session_id": item.get("session_id"), "dt": item.get("dt") }, "signal_data": {} } signal_key = item.get("key", "unknown_key") aggregate_dict[aggregate_key]["signal_data"][signal_key] = { 'signal_value': item.get('signal_value', '0.0'), "odometer": item.get('odometer', '0.0') } # 按incident_time排序 sorted_result = sorted( aggregate_dict.values(), key=lambda x: x["base_info"]["incident_time"] ) return sorted_result def aggregate_line_list_gen6(map_list): """ 按incident_time聚合事件数据,生成时间线列表 改进点: 1. 使用正确的时间字段名 2. 支持精确的时间排序 3. 处理同一时间点的多条记录 4. 添加健壮的错误处理 """ aggregated_data = {} # 遍历所有事件 for item in map_list: try: base_info = item['base_info'] # 提取需要的字段 incident_time_str = base_info.get('incident_time', '1970-01-01 00:00:00.000') speed = base_info.get('speed', '0') oneid = base_info.get('oneid', '') latitude = base_info.get('latitude', '0') longitude = base_info.get('longitude', '0') incident_name = base_info.get('incident_name', 'Unknown Incident') # 创建聚合键(使用完整时间字符串) aggregate_key = incident_time_str # 聚合处理 if aggregate_key not in aggregated_data: # 新的时间点,初始化记录 aggregated_data[aggregate_key] = { 'incident_time': incident_time_str, # 使用正确的字段名 'speed': speed, 'oneid': oneid, 'latitude': latitude, 'longitude': longitude, 'incident_names': [incident_name], # 使用复数形式,表示可能有多个 'record_count': 1 # 记录该时间点的记录数 } else: # 已存在的时间点 existing = aggregated_data[aggregate_key] # 可选:处理同一时间点不同记录的字段冲突 # 这里选择保留第一条的速度,但如果需要可以取平均值或最新值 # existing['speed'] = str((float(existing['speed']) + float(speed)) / 2) # 添加事件名称(去重) if incident_name not in existing['incident_names']: existing['incident_names'].append(incident_name) existing['record_count'] += 1 except (KeyError, TypeError) as e: print(f"Warning: Skipping item due to missing field: {e}") continue # 转换为列表形式,并按时间正序排序 def get_sort_time(record): try: time_str = record['incident_time'] if '.' in time_str: # 处理带毫秒的时间 return datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S.%f") else: # 处理不带毫秒的时间 return datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S") except (ValueError, TypeError) as e: print(f"Warning: Failed to parse time '{record['incident_time']}' for sorting: {e}") return datetime(1970, 1, 1) # 返回默认时间 # 按incident_time正序排序(从小到大) result = sorted(aggregated_data.values(), key=get_sort_time) return result def get_logging_list_gen6(map_list): """ 处理map_list数据,生成logging列表,并按incident_time正序排序 同时对每个记录的signals按name字段进行字符顺序排序 """ # 1. 首先对map_list按incident_time进行排序 def get_sort_key(item): try: incident_time_str = item['base_info']['incident_time'] # 处理时间字符串,统一格式 if '.' in incident_time_str: # 保留到毫秒级别进行排序 base_time_str = incident_time_str.split('.')[0] milliseconds = incident_time_str.split('.')[1][:6] # 取最多6位毫秒 full_time_str = f"{base_time_str}.{milliseconds}" return datetime.strptime(full_time_str, "%Y-%m-%d %H:%M:%S.%f") else: return datetime.strptime(incident_time_str, "%Y-%m-%d %H:%M:%S") except (ValueError, TypeError, KeyError) as e: print(f"Warning: Failed to parse incident_time for sorting: {e}") # 解析失败时返回一个很早的时间,确保这些记录排在最后 return datetime(1970, 1, 1) # 按incident_time正序排序(从小到大) sorted_map_list = sorted(map_list, key=get_sort_key) # 2. 处理排序后的数据 result = [] id = 0 for item in sorted_map_list: id += 1 row_data = {} row_data['id'] = id base_info = item['base_info'] # 处理时间格式 - 新格式为 "2025-11-30 20:23:05.394000" incident_time_str = base_info['incident_time'] try: # 尝试解析新格式的时间 if '.' in incident_time_str: # 移除毫秒部分,只保留到秒 base_time_str = incident_time_str.split('.')[0] dt = datetime.strptime(base_time_str, "%Y-%m-%d %H:%M:%S") else: dt = datetime.strptime(incident_time_str, "%Y-%m-%d %H:%M:%S") row_data['time'] = dt.strftime("%H:%M:%S") except (ValueError, TypeError) as e: print(f"Warning: Failed to parse incident_time '{incident_time_str}': {e}") # 使用默认时间 row_data['time'] = "00:00:00" # 处理经纬度 - 可能为 "NULL" 字符串 longitude = str(base_info.get('longitude', '')).strip() latitude = str(base_info.get('latitude', '')).strip() # 处理 "NULL" 字符串 if longitude.lower() == "null" or longitude == "": longitude = "N/A" if latitude.lower() == "null" or latitude == "": latitude = "N/A" # 格式化坐标显示 row_data['coordinates'] = f"{longitude[:12]}\n{latitude[:12]}" # 处理idc_tickcount_ms row_data['idc_tickcount_ms'] = base_info.get('idc_tickcount_ms_int', 0) # 处理速度 - 可能为 "NULL" 字符串 speed = str(base_info.get('speed', '')).strip() if speed.lower() == "null" or speed == "": speed = "0" row_data['speed'] = speed # 处理incident信息 - 新格式没有Incident__description row_data['incident'] = { "name": base_info.get('incident_name', 'Unknown Incident'), "description": "" # 使用incident_name作为描述 } # 处理信号数据 row_data['signals'] = [] for key, value in item["signal_data"].items(): signals_name_value = {} signals_name_value["name"] = key # 新格式使用signal_value字段 signal_value = value.get('signal_value', '') if signal_value is None or signal_value == "": signal_value = "N/A" signals_name_value["value"] = signal_value # 匹配到meanning的值 meaning_result=match_meaning(key,signal_value) # 新格式没有Meaning字段,使用空字符串 signals_name_value["meaning"] = meaning_result row_data['signals'].append(signals_name_value) # === 新增:对signals列表按name字段进行字符顺序排序 === row_data['signals'] = sorted(row_data['signals'], key=lambda x: x['name']) result.append(row_data) return result def convert_to_histro_data(raw_data): """ 转换原始数据为前端折线图格式(time保留%Y-%m-%d %H:%M:%S.%f格式) :param raw_data: 原始字典列表 :return: 前端所需格式的列表 """ # 步骤1:按signal分组 signal_groups = defaultdict(list) for item in raw_data: signal_groups[item["signal"]].append(item) # 步骤2:处理每个分组,构造最终数据 chart_data = [] for signal_name, items in signal_groups.items(): # 修复1:统一使用start_ts字段进行排序(因为这是时间轴数据) def sort_by_start_ts(item): return datetime.strptime(item["time"], "%Y-%m-%d %H:%M:%S.%f") sorted_items = sorted(items, key=sort_by_start_ts) # 修复3:统一使用time作为X轴时间数据(与排序字段一致) time_list = [item["time"] for item in sorted_items] # 使用start_ts作为时间轴 values_list = [float(item["value"]) for item in sorted_items] # value转数值 # 子步骤3:构造当前signal的折线图数据 chart_item = { "signalName": signal_name, "time": time_list, # X轴时间数据 "values": values_list # Y轴数值数据 } chart_data.append(chart_item) return chart_data def convert_to_histro_data_v2(raw_data): """ 转换原始数据为前端图表格式 {x: 时间, y: 数值, value: 数值} :param raw_data: 原始字典列表,需包含 "signal"、"time"、"value" 字段 :return: 字典(key=signal名称,value=对应{x,y,value}格式的列表); 若需合并所有signal为单列表,可取消注释对应逻辑 """ # 步骤1:按signal字段分组 signal_groups = defaultdict(list) for item in raw_data: signal_groups[item["signal"]].append(item) # 步骤2:处理每个分组,构造目标格式数据 chart_data = {} for signal_name, items in signal_groups.items(): # 按time字段排序(保证时间轴顺序) def sort_by_time(item): return datetime.strptime(item["time"], "%Y-%m-%d %H:%M:%S.%f") sorted_items = sorted(items, key=sort_by_time) # 构造 {x: 时间, y: 数值, value: 数值} 格式的列表 signal_item_list = [] for item in sorted_items: val = float(item["value"]) # 确保数值类型为浮点数 signal_item_list.append({ "x": item["time"], # x轴:时间字符串(对应示例中的"销量4"类标签) "y": item['valueExplanation'], # y轴:原始value数值 "value": val # value字段:与y轴数值一致(匹配示例格式) }) # ========== 新增逻辑开始 ========== # 获取排序后第一条原始数据 first_raw_item = sorted_items[0] # 判断is_pre_value_needed是否非空(处理空字符串、None、"NULL"等情况) is_needed = first_raw_item.get("is_pre_value_needed", "") if is_needed and is_needed.strip() and is_needed != "NULL": try: # 提取pre相关值并转换类型 pre_val = float(first_raw_item["pre_value"]) pre_explanation = first_raw_item["pre_valueExplanation"] first_time = first_raw_item["time"] # 在第一条数据的时间基础上减10秒 first_time_dt = datetime.strptime(first_time, "%Y-%m-%d %H:%M:%S.%f") pre_time_dt = first_time_dt - timedelta(seconds=10) pre_time_str = pre_time_dt.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] # 构造前置数据项 pre_item = { "x": '', # x轴:第一条数据的时间 "y": pre_explanation, # y轴:pre_value对应的说明 "value": pre_val, # value字段:pre_value的数值 "show":1 } # 插入到列表最前面 signal_item_list.insert(0, pre_item) except KeyError as e: print(f"警告:第一条数据缺少{e}字段,跳过前置数据插入") except ValueError as e: print(f"警告:pre_value转换浮点数失败({e}),跳过前置数据插入") # ========== 新增逻辑结束 ========== # 按signal名称存储结果 chart_data[signal_name] = signal_item_list return chart_data def match_meaning(singla_name,value): import os current_dir = os.path.dirname(os.path.abspath(__file__)) json_path = os.path.join(current_dir, "singal_value.json") with open(json_path, "r", encoding="utf-8") as f: mean_data = json.load(f) singla=singla_name.split('.')[-1] meaning_state=mean_data.get(singla,None) if meaning_state: return meaning_state[value] if meaning_state[value] else '' else: return ''