from fastapi import APIRouter, Request, Depends, HTTPException, Query from sqlalchemy.exc import IntegrityError from fastapi.responses import HTMLResponse, FileResponse from fastapi.responses import JSONResponse from database import get_db from sqlalchemy import text, exists, and_, or_, not_ from sqlalchemy.orm import Session from models import * import json import random from sqlalchemy import create_engine, select from typing import Optional from utils.StripTagsHTMLParser import * from common.db import db_event_management, db_user, db_area, db_emergency_plan from common.security import valid_access_token import traceback from utils import * from datetime import datetime, timedelta from common import YzyApi from common.db import db_dict from urllib.parse import quote import base64 from config import settings router = APIRouter() @router.post('/create') async def create_event( request: Request, db: Session = Depends(get_db), body = Depends(remove_xss_json), user_id = Depends(valid_access_token)): try: # 验证必需的字段 ''' required_fields = ['event_title', 'event_type', 'event_level', 'event_status', 'event_time', 'report_time', 'deaths', 'injuries', "missing", "event_source", "longitude", "latitude", "event_description", "address"] missing_fields = [field for field in required_fields if field not in body] if missing_fields: raise HTTPException(status_code=401, detail=f"Missing required fields: {', '.join(missing_fields)}") ''' eventId = db_event_management.get_next_event_id(db) # 未上报时清空伤亡人数 if body['casualties'] == '0': body['deaths'] = None body['injuries'] = None body['missing'] = None region_code = db_area.get_region_code_by_gps(db, body['longitude'], body['latitude']) event_base = EventBase( **body, event_code = eventId, recorded_by = user_id, region_code = region_code ) db.add(event_base) db.commit() db.refresh(event_base) # 事件跟踪表 event_tracking = EventTracking() event_tracking.event_id = event_base.id event_tracking.event_status = event_base.event_status event_tracking.event_level = event_base.event_level event_tracking.tracking_time = datetime.now() event_tracking.recorded_by = user_id event_tracking.del_flag = "0" db.add(event_tracking) db.commit() return { "code": 200, "msg": "新建事件成功", "data": eventId } except Exception as e: db.rollback() traceback.print_exc() raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}") @router.get('/list') async def get_event_list( event_type: str = Query('', description='事件类型的字典键值'), event_level: str = Query('', description='事件等级的字典键值'), event_status: str = Query('', description='事件状态的字典键值'), event_time: str = Query('', description='事发时间'), region_code: str = Query('', description='行政区划代码'), keyword: str = Query('', description='根据事件标题或描述中的关键字进行模糊搜索'), sort_by: str = Query('', description='排序字段'), sort_order: str = Query("asc", description='排序方式'), page: int = Query(1, gt=0, description='页码'), page_size: int = Query(10, gt=0, description='pageSize'), db: Session = Depends(get_db) ): try: # 应用查询条件 where = and_(EventBase.del_flag == '0') if event_type != '': where = and_(where, EventBase.event_type == event_type) if event_level != '': where = and_(where, EventBase.event_level == event_level) if event_status != '': where = and_(where, EventBase.event_status == event_status) if event_time != '': event_time = datetime.strptime(event_time, "%Y-%m-%d") event_time = event_time + timedelta(days=1) where = and_(where, EventBase.event_time.between(event_time, event_time + timedelta(days=1))) if region_code != '': where = and_(where, EventBase.region_code.like('{}%'.format(region_code))) if keyword != '': where = and_(where, or_(EventBase.event_title.like('%{}%'.format(keyword)), EventBase.address.like('%{}%'.format(keyword)))) print(where) # 计算总条目数 q = db.query(func.count(EventBase.id)) q = q.filter(where) total = q.scalar() # 执行分页查询 q = db.query(EventBase) q = q.filter(where) rows = q.order_by(EventBase.id.desc()).offset((page - 1) * page_size).limit(page_size).all() data = [ { "event_id": row.event_code, "event_title": row.event_title, "event_type": row.event_type, "event_level": row.event_level, "event_status": row.event_status, "latitude": row.latitude, "longitude": row.longitude, "address": row.address, "event_time": get_datetime_str(row.event_time) } for row in rows ] # 返回结果 return { "code": 200, "msg": "查询成功", "data": data, "total": total } except Exception as e: # 处理异常 traceback.print_exc() raise HTTPException(status_code=500, detail=str(e)) @router.get('/edit') async def get_edit_event( request: Request, event_id: str = Query(None, description='事件编号'), db: Session = Depends(get_db)): row = db.query(EventBase).filter(EventBase.event_code == event_id).first() data = get_model_dict(row) data['eventId'] = data['event_code'] data['event_time'] = get_datetime_str(data['event_time']) data['report_time'] = get_datetime_str(data['report_time']) return { "code": 200, "msg": "查询成功", "data": data } @router.post('/edit') async def post_edit_event( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db), user_id = Depends(valid_access_token)): eventId = body['eventId'] del body['eventId'] body['recorded_by'] = user_id # 未上报时清空伤亡人数 if body['casualties'] == '0': body['deaths'] = None body['injuries'] = None body['missing'] = None db.query(EventBase).filter(EventBase.event_code == eventId).update(body) db.commit() return { "code": 200, "msg": "保存事件成功" } @router.post("/uploadEventCasualties") async def uploadEventCasualties( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] del body['eventId'] body['casualties'] = '1' db.query(EventBase).filter(EventBase.event_code == eventId).update(body) db.commit() return { "code": 200, "msg": "上报伤亡情况成功" } @router.get('/detail') async def get_event_detail( request: Request, event_id: str = Query(None, description='事件编号'), db: Session = Depends(get_db)): print('event_id:',event_id) try: # 构建查询 query = db.query(EventBase) query = query.filter(EventBase.event_code == event_id) # 执行查询 row = query.first() if row is not None: return { "code": 200, "msg": "查询成功", "data": { "id": row.id, "event_id": row.event_code, "event_title": row.event_title, "event_type": row.event_type, "event_level": row.event_level, "event_status": row.event_status, "event_source": row.event_source, "event_time": get_datetime_str(row.event_time), "report_time": get_datetime_str(row.report_time), "casualties": row.casualties, "deaths": row.deaths, "injuries": row.injuries, "missing": row.missing, "reported_by": db_user.get_nick_name_by_id(db, row.recorded_by), "contact": row.contact, "event_description": row.event_description, "latitude": row.latitude, "longitude": row.longitude, "address": row.address, "plan_name": db_emergency_plan.get_plan_name_by_id(db, row.plan_id), "del_flag": row.del_flag, "summary_file": db_event_management.get_summary_file_list(db, row.id), # 事件跟踪 "event_status_tracks": db_event_management.get_event_status_track(db, row.id), # 事件等级 "event_level_tracks": db_event_management.get_event_level_track(db, row.id) } } else: return { "code": 500, "msg": "查询失败" } except Exception as e: # 处理异常 traceback.print_exc() raise HTTPException(status_code=500, detail=str(e)) @router.post('/start') async def start_event( request: Request, db: Session = Depends(get_db), body = Depends(remove_xss_json), user_id = Depends(valid_access_token)): try: event_base = db.query(EventBase).filter(EventBase.event_code == body['eventId']).first() if event_base is not None: event_base.event_status = "1" # 开始指挥 event_base.event_level= body['event_level'] event_tracking = EventTracking() event_tracking.event_id = event_base.id event_tracking.event_status = event_base.event_status event_tracking.event_level = body['event_level'] event_tracking.tracking_time = datetime.now() event_tracking.recorded_by = user_id event_tracking.del_flag = "0" db.add(event_tracking) db.commit() return { "code": 200, "msg": "开始指挥成功" } except Exception as e: # 处理异常 db.rollback() traceback.print_exc() raise HTTPException(status_code=500, detail=str(e)) @router.post('/close') async def close_event( request: Request, db: Session = Depends(get_db), body = Depends(remove_xss_json), user_id = Depends(valid_access_token)): try: # 验证必需的字段 ''' required_fields = ['eventId', 'deaths', 'injuries', 'missing', 'fileNames'] missing_fields = [field for field in required_fields if field not in body] print('missing_fields', missing_fields) if missing_fields: raise HTTPException(status_code=401, detail=f"Missing required fields: {', '.join(missing_fields)}") ''' eventId = body['eventId'] # 标记关闭状态 event_base = db.query(EventBase).filter(EventBase.event_code == eventId).first() if event_base is None: return { "code": 500, "msg": '事件不存在' } if event_base.event_status != "3": event_base.event_status = "3" event_base.del_flag = "0" # 临时事件页改为正式事件 db.commit() event_tracking = EventTracking() event_tracking.event_id = event_base.id event_tracking.event_status = event_base.event_status event_tracking.event_level = event_base.event_level event_tracking.tracking_time = datetime.now() event_tracking.recorded_by = user_id event_tracking.del_flag = "0" db.add(event_tracking) db.commit() return { "code": 200, "msg": '关闭事件成功' } except Exception as e: # 处理异常 traceback.print_exc() raise HTTPException(status_code=500, detail=str(e)) @router.post('/stop') async def stop_event( request: Request, db: Session = Depends(get_db), body = Depends(remove_xss_json)): try: eventId = body['eventId'] db.query(EventBase).filter(EventBase.event_code == eventId).update({"event_status": "2"}) db.commit() return { "code": 200, "msg": '结束指挥成功' } except Exception as e: traceback.print_exc() # 处理异常 raise HTTPException(status_code=500, detail=str(e)) @router.post('/delete') async def delete_event( request: Request, db: Session = Depends(get_db), body = Depends(remove_xss_json)): try: eventId = body['eventId'] db.query(EventBase).filter(EventBase.event_code == eventId).update({"del_flag": "2"}) db.commit() return { "code": 200, "msg": '删除事件成功' } except Exception as e: traceback.print_exc() # 处理异常 raise HTTPException(status_code=500, detail=str(e)) @router.get("/download_file", response_class=FileResponse, summary="下载总结报告") async def download_file( request: Request, file_id: int, event_id: int, db: Session = Depends(get_db) ): row = db.query(EventFile).filter(and_(EventFile.del_flag == '0', EventFile.id == file_id, EventFile.event_id == event_id)).first() if row is not None: return FileResponse(row.file_path) # 小屏通知栏显示的最新时间 @router.get("/notice_bar") async def notice_bar( request: Request, db: Session = Depends(get_db) ): try: row = db.query(EventBase).filter(and_(EventBase.del_flag == '0', EventBase.event_status.in_([0, 1]))).order_by(EventBase.event_time.desc()).first() if row is not None: return { 'code': 200, 'msg': '查询成功', 'data': { 'event_id': row.event_code, 'event_title': row.event_title } } else: return { 'code': 500, 'msg': '查询失败' } except Exception as e: traceback.print_exc() # 处理异常 raise HTTPException(status_code=500, detail=str(e)) # 列出已登记(未开始指挥)的事件列表 @router.post("/list_registered") async def list_registered( request: Request, db: Session = Depends(get_db) ): where = and_(EventBase.del_flag == '0', EventBase.event_status == '0') rows = db.query(EventBase).filter(where).order_by(EventBase.event_time.asc()).all() data = [ { "event_id": row.event_code, "event_title": row.event_title, "event_type": row.event_type, "event_level": row.event_level, "event_status": row.event_status, "latitude": row.latitude, "longitude": row.longitude, "address": row.address, "event_time": get_datetime_str(row.event_time) } for row in rows ] # 返回结果 return { "code": 200, "msg": "查询成功", "data": data } # 登记事发地点 @router.post("/save_address") async def list_registered( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] row = db.query(EventBase).filter(EventBase.event_code == eventId).first() if row is None: return { "code": 500, "msg": "事件编号不存在" } row.address = body['address'] row.longitude = body['longitude'] row.latitude = body['latitude'] db.commit() return { "code": 200, "msg": "登记事发地点成功" } # 匹配预案 @router.post("/march_emergency_plan") async def martch_emergency_plan( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] plan_id = "" response_level = "" ''' 匹配过程待定 ''' row = db.query(EmergencyPlan).filter(EmergencyPlan.id == 16).filter(EmergencyPlan.del_flag == "0").first() if row is None: return { "code": 500, "msg": "无法匹配" } plan_id = row.plan_number plan_name = row.plan_name response_level = row.response_level return { "code": 200, "msg": "匹配预案成功", "data": { "eventId": eventId, "plan_id": plan_id, "plan_name": plan_name, "response_level": response_level } } # 启动预案 @router.post("/lauch_emergency_plan") async def lauch_emergency_plan( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] plan_id = body['plan_id'] response_level = body['response_level'] event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first() if event_row is None: return { "code": 500, "msg": "事件编号不存在" } plan_row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).first() if plan_row is None: return { "code": 500, "msg": "预案不存在" } # 绑定预案ID和响应等级 event_row.plan_id = plan_row.plan_number event_row.response_level = response_level event_row.del_flag = "0" # 临时事件改为正式事件 db.commit() return { "code": 200, "msg": "启动预案成功" } # 预案任务下发 @router.post("/send_emergency_plan_task_by_yzy") async def send_emergency_plan_task_by_yzy( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first() if event_row is None: return { "code": 500, "msg": "事件编号不存在" } event_info = get_model_dict(event_row) plan_id = event_info['plan_id'] response_level = db_dict.get_dict_label(db, "response_level", event_info['response_level']) if plan_id is None or plan_id == '': return { "code": 500, "msg": "未关联预案" } row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).first() if row is None: return { "code": 500, "msg": "没有匹配的预案" } plan_info = get_model_dict(row) plan_name = plan_info['plan_name'] rows = db.query(EmergencyUnit).filter(EmergencyUnit.plan_id == plan_id).order_by(EmergencyUnit.dept_order.asc()).all() for row in rows: dept_id = row.dept_id dept_name = row.dept_name row_exists = db.query(EventEmergencyNotify).filter(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId, EventEmergencyNotify.dept_id == dept_id)).first() if row_exists is not None: continue # 通过通讯录匹配相关负责人 user_row = db.query(SysUser).filter(SysUser.user_id == 1).first() user_id = user_row.user_id user_name = user_row.user_name nick_name = user_row.nick_name yzy_user_id = "eb4kehgy6wj4qn0jhx1dk6" # 暂时写死梦梅的账号 yzy_content = "{},您好!《{}》现已全面启动,特此通知您单位迅速响应,全力做好预案工作要点:{}".format(row.dept_name, plan_info['plan_name'], row.content) event_emergency_notify = EventEmergencyNotify( event_id = eventId, plan_id = plan_id, dept_id = dept_id, dept_name = dept_name, user_id = user_id, user_name = user_name, nick_name = nick_name, yzy_user_id = yzy_user_id, yzy_content = yzy_content, sent_time = datetime.now(), sent_status = 0 ) db.add(event_emergency_notify) db.commit() db.refresh(event_emergency_notify) description = "预案名称: " + plan_name + "\n响应级别:" + response_level + "\n消息内容: "+yzy_content ''' yzy_callback_url = quote("http://19.155.220.206/yjxp/#/yzy-callback") state_json = { "redirect_url": "http://19.155.220.206/yjxp/#/leader/index" # 业务页面 } state_str = json.dumps(state_json) state = base64.b64encode(state_str).decode('utf-8') detail_url = "https://open.weixin.qq.com/connect/Oauth2/authorize?appid=wld341060039&redirect_uri={}&response_type=code&scope=snsapi_base&agentid=1004302&state={}#wechat_redirect".format(yzy_callback_url, state) ''' # redirect_url = "http://19.155.220.206/yjxp/#/leader/index" # 业务页面 redirect_url = "{}/#/leader/index".format(settings.YJXP_WEB_ROOT_PATH) # 业务页面 detail_url = YzyApi.format_redirect_url(redirect_url) try: resp = YzyApi.send_textcard_message([yzy_user_id], "预案响应消息", description, detail_url) if resp['errcode'] == 0: event_emergency_notify.sent_status = 1 # 发送成功 else: event_emergency_notify.sent_status = 9 # 发送失败 db.commit() except Exception: pass return { "code": 200, "msg": "预案任务下发成功" } # 获取预案通知 @router.post("/emergency_plan_task_list") async def emergency_plan_task_list( request: Request, body = Depends(remove_xss_json), db: Session = Depends(get_db) ): eventId = body['eventId'] event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first() if event_row is None: return { "code": 500, "msg": "事件编号不存在" } event_info = get_model_dict(event_row) plan_id = event_info['plan_id'] if plan_id is None or plan_id == '': return { "code": 500, "msg": "未关联预案" } where = and_(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId)) rows = db.query(EventEmergencyNotify).filter(where).order_by(EventEmergencyNotify.id.asc()).all() data = [ { "dept_name": row.dept_name, "sent_time": get_datetime_str(row.sent_time), "sent_status": row.sent_status, "sent_status_text": get_sent_status_text(row.sent_status), "yzy_content": row.yzy_content, "nick_name": row.nick_name } for row in rows ] # 返回结果 return { "code": 200, "msg": "查询成功", "data": data } def get_sent_status_text(sent_status) -> str: if sent_status == 0: return '暂未发送' elif sent_status == 1: return '发送成功' elif sent_status == 0: return '发送失败' else: return str(sent_status)