diff --git a/app/cross_eva_views.py b/app/cross_eva_views.py index 7f518d4..6e85982 100644 --- a/app/cross_eva_views.py +++ b/app/cross_eva_views.py @@ -85,6 +85,12 @@ def cross_problems_detail_api(): def update_cross_examine_record_state_api(): return update_cross_examine_record_state(request.json) + +@app.route('/api/explode_cross_problem_detail', methods=['GET']) +def explode_cross_problem_detail_api(): + return explode_cross_problem_detail(dict(request.args)) + + from app.user_views import * from app.views_task import * from app.views_workstation import * diff --git a/app/cross_evaluate_worker.py b/app/cross_evaluate_worker.py index 0b406bf..19efbcf 100644 --- a/app/cross_evaluate_worker.py +++ b/app/cross_evaluate_worker.py @@ -450,3 +450,51 @@ def update_cross_examine_record_state(params): return json.dumps(make_common_res(0, 'ok')) return json.dumps(make_common_res(11, '修改失败,请检查后重试')) + +# 离线导出巡检路口指标明细表 +def explode_cross_problem_detail(params): + nodeid = check_param(params, 'nodeid') + if not nodeid: + return json.dumps(make_common_res(2, '缺少城市信息, 请刷新后重试')) + area_id = check_param(params, 'area_id') + if not area_id: + return json.dumps(make_common_res(3, '缺少辖区信息, 请刷新后重试')) + time_range = check_param(params, 'time_range') + if not time_range: + return json.dumps(make_common_res(4, '缺少时间范围信息, 请刷新后重试')) + start_date = check_param(params, 'start_date') + if not start_date: + return json.dumps(make_common_res(5, '缺少开始时间, 请选择开始时间')) + end_date = check_param(params, 'end_date') + if not end_date: + return json.dumps(make_common_res(6, '缺少结束时间, 请选择结束时间')) + excel = check_param(params, 'excel') + if not excel: + excel = 0 + excel = int(excel) + + routing_crosses = db_tmnet.query_routing_crosses(nodeid, area_id) + routing_crosses_dict = {item['crossid']: item for item in routing_crosses} + cross_roads_dir_dict = gen_crossids_roads_dir_dict_by_mysql([item['crossid'] for item in routing_crosses], nodeid) + for crossid in routing_crosses_dict.keys(): + routing_crosses_dict[crossid]['roads_dir_dict'] = cross_roads_dir_dict[crossid] + + tp_start = 't' + str(int(str(time_range.split('-')[0]).split(':')[0]) * 100 + int(str(time_range.split('-')[0]).split(':')[1])) + tp_end = int(str(time_range.split('-')[1]).split(':')[0]) * 100 + int(str(time_range.split('-')[1]).split(':')[1]) + + date_list = generate_date_range(start_date, end_date) + all_cross_data = [] + for crossid in routing_crosses_dict.keys(): + days_data = db_cross.query_cross_delay_info(crossid, nodeid, date_list, tp_start) + days_pb_list = parse_data2pb(days_data) + cross_data_list = parse_cross_delay_detail_list(routing_crosses_dict[crossid], days_pb_list, time_range) + all_cross_data.extend(cross_data_list) + + if excel == 1: + return export_excel(all_cross_data) + + res = make_common_res(0, 'ok') + res['data'] = all_cross_data + return json.dumps(clean_dict_nan(res, '-'), ensure_ascii=False) + + diff --git a/app/eva_common.py b/app/eva_common.py index bc5b66d..d774286 100644 --- a/app/eva_common.py +++ b/app/eva_common.py @@ -14,6 +14,7 @@ import random from openpyxl import Workbook from openpyxl.styles import Alignment +from openpyxl.utils import get_column_letter import proto.xlcomm_pb2 as pb from app.common_worker import * @@ -2371,4 +2372,173 @@ def query_cross_delay_info_controller_export_excel(road_flow_delay_infos, road_f file_stream, mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', as_attachment=True, - download_name=f"路口诊断指标.xlsx") \ No newline at end of file + download_name=f"路口诊断指标.xlsx") + + +def parse_cross_delay_detail_list(cross_info, delay_info_list, time_range): + cross_id = cross_info['crossid'] + cross_name = cross_info['name'] + weekday_str = '全周' + max_car_num = 0 + for item in delay_info_list: + if item['data'].delay_info.car_num > max_car_num: + max_car_num = item['data'].delay_info.car_num + data_list = [] + for item in delay_info_list: + relative_flow_rate = round(item['data'].delay_info.car_num / max_car_num, 2) if max_car_num > 0 else 0 + item_dict = { + 'cross_id': cross_id, + 'cross_name': cross_name, + 'weekday': weekday_str, + 'time_range': time_range, + 'day': item['day'], + 'service_level': calc_service_level(item['data'].delay_info.delay_time, item['data'].delay_info.stop_times) if item['data'].delay_info.car_num >= 10 else '-', + 'stop_times': round(item['data'].delay_info.stop_times, 2) if item['data'].delay_info.car_num >= 10 else '-', + 'high_park_percent': item['data'].delay_info.high_park_percent if item['data'].delay_info.car_num >= 10 else '-', + 'park_time': item['data'].delay_info.park_time if item['data'].delay_info.car_num >= 10 else '-', + 'delay_time': item['data'].delay_info.delay_time if item['data'].delay_info.car_num >= 10 else '-', + 'speed': round(item['data'].delay_info.speed / 100, 2) if item['data'].delay_info.car_num >= 10 else '-', + 'move_speed': round(item['data'].delay_info.move_speed / 100, 2) if item['data'].delay_info.car_num >= 10 else '-', + 'relative_flow_rate': relative_flow_rate if item['data'].delay_info.car_num >= 10 else '-', + 'flow': item['data'].delay_info.car_num, + 'jam_index': round(item['data'].delay_info.jam_index, 2) if item['data'].delay_info.car_num >= 10 else '-', + 'imbalance_index': round(item['data'].delay_info.imbalance_index, 2) if item['data'].delay_info.car_num >= 10 else '-', + 'service_level_color': 0, + 'stop_times_color': 0, + 'high_park_percent_color': 0, + 'park_time_color': 0, + 'delay_time_color': 0, + 'speed_color': 0, + 'move_speed_color': 0, + 'relative_flow_rate_color': 0, + 'flow_color': 0, + 'jam_index_color': 0, + 'imbalance_index_color': 0, + 'stop_times_rate': 0, + 'high_park_percent_rate': 0, + 'park_time_rate': 0, + 'delay_time_rate': 0, + 'speed_rate': 0, + 'move_speed_rate': 0, + 'relative_flow_rate_rate': 0, + 'flow_rate': 0, + 'jam_index_rate': 0, + 'imbalance_index_rate': 0, + } + data_list.append(item_dict) + + for i in range(len(data_list)-1, -1, -1): + if i != 0: + item_data = data_list[i] + prev_data = data_list[i-1] + if item_data['service_level'] != '-' and prev_data['service_level'] != '-': + if item_data['service_level'] < prev_data['service_level']: + item_data['service_level_color'] = 2 + elif item_data['service_level'] > prev_data['service_level']: + item_data['service_level_color'] = 1 + for key in ('delay_time', 'stop_times', 'high_park_percent', 'park_time', 'relative_flow_rate', 'flow', 'jam_index', 'imbalance_index'): + if item_data[key] == '-' or prev_data[key] == '-': + continue + if prev_data[key] != 0: + rate = round((item_data[key] - prev_data[key]) / prev_data[key] * 100, 2) + item_data[key + '_rate'] = rate + if rate > 20: + item_data[key + '_color'] = 1 + elif rate < -20: + item_data[key + '_color'] = 2 + for key in ('speed', 'move_speed'): + if item_data[key] == '-' or prev_data[key] == '-': + continue + if prev_data[key] != 0: + rate = round((item_data[key] - prev_data[key]) / prev_data[key] * 100, 2) + item_data[key + '_rate'] = rate + if rate > 20: + item_data[key + '_color'] = 2 + elif rate < -20: + item_data[key + '_color'] = 1 + return data_list + + +def export_excel(all_cross_data): + wb = Workbook() + sheet1 = wb.active + table_header = [ + {'A1': '路口ID'}, + {'B1': '路口名称'}, + {'C1': '运行日期'}, + {'D1': '时段'}, + {'E1': '停车次数'}, + {'F1': '停车次数变化率'}, + {'G1': '多次停车率%'}, + {'H1': '多次停车率变化率'}, + {'I1': '停车时间(秒)'}, + {'J1': '停车时间变化率'}, + {'K1': '延迟时间(秒)'}, + {'L1': '延迟时间变化率'}, + {'M1': '平均速度(KM/H)'}, + {'N1': '平均速度变化率'}, + {'O1': '不停车速度(KM/H)'}, + {'P1': '不停车速度变化率'}, + {'Q1': '相对流量'}, + {'R1': '相对流量变化率'}, + {'S1': '拥堵指数'}, + {'T1': '拥堵指数变化率'}, + {'U1': '路口失衡指数'}, + {'V1': '路口失衡指数变化率'}, + {'W1': '服务水平'}, + {'X1': '服务水平变化情况'} + ] + for item in table_header: + for k, v in item.items(): + sheet1[k] = v + sheet1[k].alignment = Alignment(horizontal='center', vertical='center') + # 自动调整列宽 + for col_idx, header in enumerate(table_header, 1): + # 计算列宽:可以根据字体大小适当调整这个公式 + # 通常一个中文字符占2个单位宽度,英文字符占1个单位宽度 + column_width = len(list(header.values())[0].encode('utf-8')) * 1.2 # 粗略估算 + adjusted_width = min(max(column_width, 10), 50) # 设置最小和最大宽度限制 + sheet1.column_dimensions[get_column_letter(col_idx)].width = adjusted_width + + for item in all_cross_data: + service_level_color = '-' + if item['service_level_color'] == 1: + service_level_color = '恶化' + elif item['service_level_color'] == 2: + service_level_color = '优化' + item_data = [ + item['cross_id'], + item['cross_name'], + item['weekday'], + item['time_range'], + item['stop_times'], + item['stop_times_rate'], + item['high_park_percent'], + item['high_park_percent_rate'], + item['park_time'], + item['park_time_rate'], + item['delay_time'], + item['delay_time_rate'], + item['speed'], + item['speed_rate'], + item['move_speed'], + item['move_speed_rate'], + item['relative_flow_rate'], + item['relative_flow_rate_rate'], + item['jam_index'], + item['jam_index_rate'], + item['imbalance_index'], + item['imbalance_index_rate'], + item['service_level'], + service_level_color + ] + sheet1.append(item_data) + + file_stream = io.BytesIO() + wb.save(file_stream) + file_stream.seek(0) # 将指针移到文件开头 + return send_file( + file_stream, + mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + as_attachment=True, + download_name=f"路口信息明细指标.xlsx")