event.py 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. from fastapi import APIRouter, Request, Depends, HTTPException, Query, BackgroundTasks,status
  2. from sqlalchemy.exc import IntegrityError
  3. from fastapi.responses import HTMLResponse, FileResponse
  4. from fastapi.responses import JSONResponse
  5. from database import get_db
  6. from sqlalchemy import text, exists, and_, or_, not_
  7. from sqlalchemy.orm import Session
  8. from models import *
  9. import json
  10. import random
  11. from sqlalchemy import create_engine, select
  12. from typing import Optional
  13. from utils.StripTagsHTMLParser import *
  14. from common.db import db_event_management, db_user, db_area, db_emergency_plan, db_msg_center, db_yzy
  15. from common.security import valid_access_token
  16. import traceback
  17. from utils import *
  18. from datetime import datetime, timedelta
  19. from common import YzyApi
  20. from common.db import db_dict
  21. from urllib.parse import quote
  22. import base64
  23. from config import settings
  24. from extensions import logger
  25. import os
  26. from common.enc import mpfun
  27. router = APIRouter()
  28. @router.post('/create')
  29. async def create_event(
  30. request: Request,
  31. db: Session = Depends(get_db),
  32. body = Depends(remove_xss_json),
  33. user_id = Depends(valid_access_token)):
  34. try:
  35. # 验证必需的字段
  36. '''
  37. required_fields = ['event_title', 'event_type', 'event_level', 'event_status', 'event_time', 'report_time',
  38. 'deaths', 'injuries', "missing", "event_source", "longitude", "latitude", "event_description", "address"]
  39. missing_fields = [field for field in required_fields if field not in body]
  40. if missing_fields:
  41. raise HTTPException(status_code=401, detail=f"Missing required fields: {', '.join(missing_fields)}")
  42. '''
  43. eventId = db_event_management.get_next_event_id(db)
  44. # 未上报时清空伤亡人数
  45. if body['casualties'] == '0' or body['casualties'] == '':
  46. body['deaths'] = None
  47. body['injuries'] = None
  48. body['missing'] = None
  49. body['casualties'] == '0'
  50. region_code = db_area.get_region_code_by_gps(db, body['longitude'], body['latitude'])
  51. event_base = EventBase(
  52. **body,
  53. event_code = eventId,
  54. recorded_by = user_id,
  55. region_code = region_code,
  56. create_time = datetime.now()
  57. )
  58. db.add(event_base)
  59. db.commit()
  60. db.refresh(event_base)
  61. # 事件跟踪表
  62. event_tracking = EventTracking()
  63. event_tracking.event_id = event_base.id
  64. event_tracking.event_status = event_base.event_status
  65. event_tracking.event_level = event_base.event_level
  66. event_tracking.tracking_time = datetime.now()
  67. event_tracking.recorded_by = user_id
  68. event_tracking.del_flag = "0"
  69. db.add(event_tracking)
  70. db.commit()
  71. # 发送粤政易事件
  72. # send_yzy_msg(db, event_base, user_id)
  73. return {
  74. "code": 200,
  75. "msg": "新建事件成功",
  76. "data": eventId
  77. }
  78. except Exception as e:
  79. db.rollback()
  80. traceback.print_exc()
  81. raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
  82. # 发送粤政易消息
  83. def send_yzy_msg(db: Session, event_base: EventBase, user_id: int) -> None:
  84. to_user_id = event_base.recorded_by
  85. user_info = db_user.get_user_info(db, to_user_id)
  86. yzy_account = user_info.yzy_account
  87. yzy_userid = db_yzy.get_userid_by_account(db, yzy_account)
  88. create_time = get_datetime_str(event_base.event_time)
  89. detail_url = "{}{}{}".format(settings.YZY_WEB_ROOT, "/yjxp/#/event/detail?event_id=", event_base.event_code)
  90. description = "事件名称: " + event_base.event_title + "\n事件等级:" + create_time + "\n事发地点: " + event_base.address
  91. data = {
  92. "yzy_userid": yzy_userid,
  93. "mobile": yzy_account,
  94. "content": description,
  95. "recorded_by": user_id,
  96. "detail_url": detail_url,
  97. "foreign_key": event_base.id,
  98. "from_scenario": "event_base",
  99. "title": "事件接报"
  100. }
  101. YzyApi.add_to_msg_queue(db, data)
  102. # db_msg_center.add_message(db, "事件接报", recv_userid, "事件接报提醒", description, event_base.event_code, 'event_base')
  103. @router.get('/list')
  104. async def get_event_list(
  105. event_type: str = Query('', description='事件类型的字典键值'),
  106. event_level: str = Query('', description='事件等级的字典键值'),
  107. event_status: str = Query('', description='事件状态的字典键值'),
  108. event_time: str = Query('', description='事发时间'),
  109. region_code: str = Query('', description='行政区划代码'),
  110. keyword: str = Query('', description='根据事件标题或描述中的关键字进行模糊搜索'),
  111. sort_by: str = Query('', description='排序字段'),
  112. sort_order: str = Query("asc", description='排序方式'),
  113. page: int = Query(1, gt=0, description='页码'),
  114. page_size: int = Query(10, gt=0, description='pageSize'),
  115. db: Session = Depends(get_db)
  116. ):
  117. try:
  118. # 应用查询条件
  119. where = and_(EventBase.del_flag == '0')
  120. if event_type != '':
  121. where = and_(where, EventBase.event_type == event_type)
  122. if event_level != '':
  123. where = and_(where, EventBase.event_level == event_level)
  124. if event_status != '':
  125. where = and_(where, EventBase.event_status == event_status)
  126. if event_time != '':
  127. event_time = datetime.strptime(event_time, "%Y-%m-%d")
  128. # event_time = event_time + timedelta(days=1)
  129. where = and_(where, EventBase.event_time.between(event_time, event_time + timedelta(days=1) - timedelta(microseconds=1)))
  130. if region_code != '':
  131. where = and_(where, EventBase.region_code.like('{}%'.format(region_code)))
  132. if keyword != '':
  133. where = and_(where, or_(EventBase.event_title.like('%{}%'.format(keyword)), EventBase.address.like('%{}%'.format(keyword))))
  134. print(where)
  135. # 计算总条目数
  136. q = db.query(func.count(EventBase.id))
  137. q = q.filter(where)
  138. total = q.scalar()
  139. # 执行分页查询
  140. q = db.query(EventBase)
  141. q = q.filter(where)
  142. rows = q.order_by(EventBase.id.desc()).offset((page - 1) * page_size).limit(page_size).all()
  143. data = [
  144. {
  145. "event_id": row.event_code,
  146. "event_title": row.event_title,
  147. "event_type": row.event_type,
  148. "event_level": row.event_level,
  149. "event_status": row.event_status,
  150. "latitude": row.latitude,
  151. "longitude": row.longitude,
  152. "address": row.address,
  153. "event_time": get_datetime_str(row.event_time),
  154. "create_time": get_datetime_str(row.create_time),
  155. }
  156. for row in rows
  157. ]
  158. # 返回结果
  159. return {
  160. "code": 200,
  161. "msg": "查询成功",
  162. "data": data,
  163. "total": total
  164. }
  165. except Exception as e:
  166. # 处理异常
  167. traceback.print_exc()
  168. raise HTTPException(status_code=500, detail=str(e))
  169. @router.get('/edit')
  170. async def get_edit_event(
  171. request: Request,
  172. event_id: str = Query(None, description='事件编号'),
  173. db: Session = Depends(get_db)):
  174. row = db.query(EventBase).filter(EventBase.event_code == event_id).first()
  175. data = get_model_dict(row)
  176. data['eventId'] = data['event_code']
  177. data['event_time'] = get_datetime_str(data['event_time'])
  178. data['report_time'] = get_datetime_str(data['report_time'])
  179. return {
  180. "code": 200,
  181. "msg": "查询成功",
  182. "data": data
  183. }
  184. @router.post('/edit')
  185. async def post_edit_event(
  186. request: Request,
  187. body = Depends(remove_xss_json),
  188. db: Session = Depends(get_db),
  189. user_id = Depends(valid_access_token)):
  190. try:
  191. eventId = body['eventId']
  192. del body['eventId']
  193. body['recorded_by'] = user_id
  194. # 未上报时清空伤亡人数
  195. if body['casualties'] == '0':
  196. body['deaths'] = None
  197. body['injuries'] = None
  198. body['missing'] = None
  199. if 'deaths' in body or 'injuries' in body or 'missing' in body:
  200. body['casualties'] = '1'
  201. data = {
  202. "casualties": body['casualties'],
  203. "deaths": body['deaths'],
  204. "injuries": body['injuries'],
  205. "missing": body['missing'],
  206. "recorded_by": body['recorded_by'],
  207. "event_title": body["event_title"],
  208. "event_type": body["event_type"],
  209. "event_level": body["event_level"],
  210. "event_status": body["event_status"],
  211. "address": body["address"],
  212. "event_time": body["event_time"],
  213. "contact": body["contact"],
  214. "report_time": body["report_time"],
  215. "event_source": body["event_source"],
  216. "event_description": body["event_description"],
  217. }
  218. db.query(EventBase).filter(EventBase.event_code == eventId).update(data)
  219. db.commit()
  220. return {
  221. "code": 200,
  222. "msg": "保存事件成功"
  223. }
  224. except Exception as e:
  225. # 处理异常
  226. traceback.print_exc()
  227. raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(e))
  228. @router.post("/uploadEventCasualties")
  229. async def uploadEventCasualties(
  230. request: Request,
  231. body = Depends(remove_xss_json),
  232. db: Session = Depends(get_db)
  233. ):
  234. eventId = body['eventId']
  235. del body['eventId']
  236. body['casualties'] = '1'
  237. db.query(EventBase).filter(EventBase.event_code == eventId).update(body)
  238. db.commit()
  239. return {
  240. "code": 200,
  241. "msg": "上报伤亡情况成功"
  242. }
  243. @router.get('/detail')
  244. async def get_event_detail(
  245. request: Request,
  246. event_id: str = Query(None, description='事件编号'),
  247. db: Session = Depends(get_db)):
  248. print('event_id:',event_id)
  249. try:
  250. # 构建查询
  251. query = db.query(EventBase)
  252. query = query.filter(EventBase.event_code == event_id)
  253. # 执行查询
  254. row = query.first()
  255. if row is not None:
  256. return {
  257. "code": 200,
  258. "msg": "查询成功",
  259. "data": {
  260. "id": row.id,
  261. "event_id": row.event_code,
  262. "event_title": row.event_title,
  263. "event_type": row.event_type,
  264. "event_level": row.event_level,
  265. "event_status": row.event_status,
  266. "event_source": row.event_source,
  267. "event_time": get_datetime_str(row.event_time),
  268. "report_time": get_datetime_str(row.report_time),
  269. "casualties": row.casualties,
  270. "deaths": row.deaths,
  271. "injuries": row.injuries,
  272. "missing": row.missing,
  273. "reported_by": db_user.get_nick_name_by_id(db, row.recorded_by),
  274. "contact": row.contact,
  275. "event_description": row.event_description,
  276. "latitude": row.latitude,
  277. "longitude": row.longitude,
  278. "address": row.address,
  279. "contact": row.contact,
  280. "create_time": get_datetime_str(row.create_time),
  281. # 关联预案
  282. "plan_id": row.plan_id,
  283. "plan_name": db_emergency_plan.get_plan_name_by_id(db, row.plan_id),
  284. "plan_files": db_emergency_plan.get_plan_file_list(db, row.plan_id),
  285. "del_flag": row.del_flag,
  286. # 总结报告
  287. "summary_file": db_event_management.get_summary_file_list(db, row.id),
  288. # 事件跟踪
  289. "event_status_tracks": db_event_management.get_event_status_track(db, row.id),
  290. # 事件等级
  291. "event_level_tracks": db_event_management.get_event_level_track(db, row.id),
  292. # 预案通知下发
  293. "emergency_notify_count": db_event_management.get_emergency_notify_count(db, row.event_code)
  294. }
  295. }
  296. else:
  297. return {
  298. "code": 500,
  299. "msg": "查询失败"
  300. }
  301. except Exception as e:
  302. # 处理异常
  303. traceback.print_exc()
  304. raise HTTPException(status_code=500, detail=str(e))
  305. @router.post('/start')
  306. async def start_event(
  307. request: Request,
  308. db: Session = Depends(get_db),
  309. body = Depends(remove_xss_json),
  310. user_id = Depends(valid_access_token)):
  311. try:
  312. event_base = db.query(EventBase).filter(EventBase.event_code == body['eventId']).first()
  313. if event_base is not None:
  314. event_base.event_status = "1" # 开始指挥
  315. event_base.event_level= body['event_level']
  316. event_tracking = EventTracking()
  317. event_tracking.event_id = event_base.id
  318. event_tracking.event_status = event_base.event_status
  319. event_tracking.event_level = body['event_level']
  320. event_tracking.tracking_time = datetime.now()
  321. event_tracking.recorded_by = user_id
  322. event_tracking.del_flag = "0"
  323. db.add(event_tracking)
  324. db.commit()
  325. return {
  326. "code": 200,
  327. "msg": "开始指挥成功"
  328. }
  329. except Exception as e:
  330. # 处理异常
  331. db.rollback()
  332. traceback.print_exc()
  333. raise HTTPException(status_code=500, detail=str(e))
  334. @router.post('/close')
  335. async def close_event(
  336. request: Request,
  337. db: Session = Depends(get_db),
  338. body = Depends(remove_xss_json),
  339. user_id = Depends(valid_access_token)):
  340. try:
  341. # 验证必需的字段
  342. '''
  343. required_fields = ['eventId', 'deaths', 'injuries', 'missing', 'fileNames']
  344. missing_fields = [field for field in required_fields if field not in body]
  345. print('missing_fields', missing_fields)
  346. if missing_fields:
  347. raise HTTPException(status_code=401, detail=f"Missing required fields: {', '.join(missing_fields)}")
  348. '''
  349. eventId = body['eventId']
  350. # 标记关闭状态
  351. event_base = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  352. if event_base is None:
  353. return {
  354. "code": 500,
  355. "msg": '事件不存在'
  356. }
  357. if event_base.event_status != "3":
  358. event_base.event_status = "3"
  359. event_base.del_flag = "0" # 临时事件页改为正式事件
  360. event_base.casualties = 1 # 伤亡情况已上报
  361. db.commit()
  362. event_tracking = EventTracking()
  363. event_tracking.event_id = event_base.id
  364. event_tracking.event_status = event_base.event_status
  365. event_tracking.event_level = event_base.event_level
  366. event_tracking.tracking_time = datetime.now()
  367. event_tracking.recorded_by = user_id
  368. event_tracking.del_flag = "0"
  369. db.add(event_tracking)
  370. db.commit()
  371. if 'fileNames' in body:
  372. # 删除旧数据
  373. db.query(EventFile).filter(and_(EventFile.foreign_key == eventId, EventFile.from_scenario == 'event_summary_file')).delete()
  374. event_files = [
  375. EventFile(
  376. event_id=event_base.id,
  377. file_name=fileName["name"], # 使用 fileName["name"] 作为文件名
  378. file_path=f'/data/upload/mergefile/uploads/{fileName["url"]}',
  379. file_size = os.path.getsize(f'/data/upload/mergefile/uploads/{fileName["url"]}'),
  380. storage_file_name=fileName["url"],
  381. foreign_key=event_base.event_code,
  382. from_scenario="event_summary_file",
  383. update_time=datetime.now(),
  384. create_time=datetime.now(),
  385. del_flag='0'
  386. )
  387. for fileName in body['fileNames'] # body['fileNames'] 现在是一个包含对象的数组,每个对象都有 'name' 和 'url' 属性
  388. ]
  389. db.add_all(event_files)
  390. db.commit()
  391. return {
  392. "code": 200,
  393. "msg": '关闭事件成功'
  394. }
  395. except Exception as e:
  396. # 处理异常
  397. traceback.print_exc()
  398. raise HTTPException(status_code=500, detail=str(e))
  399. @router.post('/stop')
  400. async def stop_event(
  401. request: Request,
  402. db: Session = Depends(get_db),
  403. body = Depends(remove_xss_json)):
  404. try:
  405. eventId = body['eventId']
  406. db.query(EventBase).filter(EventBase.event_code == eventId).update({"event_status": "2"})
  407. db.commit()
  408. return {
  409. "code": 200,
  410. "msg": '结束指挥成功'
  411. }
  412. except Exception as e:
  413. traceback.print_exc()
  414. # 处理异常
  415. raise HTTPException(status_code=500, detail=str(e))
  416. @router.post('/delete')
  417. async def delete_event(
  418. request: Request,
  419. db: Session = Depends(get_db),
  420. body = Depends(remove_xss_json)):
  421. try:
  422. eventId = body['eventId']
  423. db.query(EventBase).filter(EventBase.event_code == eventId).update({"del_flag": "2"})
  424. db.commit()
  425. return {
  426. "code": 200,
  427. "msg": '删除事件成功'
  428. }
  429. except Exception as e:
  430. traceback.print_exc()
  431. # 处理异常
  432. raise HTTPException(status_code=500, detail=str(e))
  433. @router.get("/download_file", response_class=FileResponse, summary="下载总结报告")
  434. async def download_file(
  435. request: Request,
  436. file_id: int,
  437. event_id: int,
  438. db: Session = Depends(get_db)
  439. ):
  440. row = db.query(EventFile).filter(and_(EventFile.del_flag == '0', EventFile.id == file_id, EventFile.event_id == event_id)).first()
  441. if row is not None:
  442. return FileResponse(row.file_path)
  443. # 小屏通知栏显示的最新时间
  444. @router.get("/notice_bar")
  445. async def notice_bar(
  446. request: Request,
  447. db: Session = Depends(get_db)
  448. ):
  449. try:
  450. row = db.query(EventBase).filter(and_(EventBase.del_flag == '0', EventBase.event_title != '', EventBase.event_status.in_([0, 1]))).order_by(EventBase.event_time.desc()).first()
  451. if row is not None:
  452. return {
  453. 'code': 200,
  454. 'msg': '查询成功',
  455. 'data': {
  456. 'event_id': row.event_code,
  457. 'event_title': row.event_title
  458. }
  459. }
  460. else:
  461. return {
  462. 'code': 500,
  463. 'msg': '查询失败'
  464. }
  465. except Exception as e:
  466. traceback.print_exc()
  467. # 处理异常
  468. raise HTTPException(status_code=500, detail=str(e))
  469. # 列出已登记(未开始指挥)的事件列表
  470. @router.post("/list_registered")
  471. async def list_registered(
  472. request: Request,
  473. db: Session = Depends(get_db)
  474. ):
  475. where = and_(EventBase.del_flag == '0', EventBase.event_status == '0')
  476. rows = db.query(EventBase).filter(where).order_by(EventBase.event_time.asc()).all()
  477. data = [
  478. {
  479. "event_id": row.event_code,
  480. "event_title": row.event_title,
  481. "event_type": row.event_type,
  482. "event_level": row.event_level,
  483. "event_status": row.event_status,
  484. "latitude": row.latitude,
  485. "longitude": row.longitude,
  486. "address": row.address,
  487. "event_time": get_datetime_str(row.event_time),
  488. "create_time": get_datetime_str(row.create_time)
  489. }
  490. for row in rows
  491. ]
  492. # 返回结果
  493. return {
  494. "code": 200,
  495. "msg": "查询成功",
  496. "data": data
  497. }
  498. # 列出有个不分页的查询 不是临时事件、未结束、未关闭的事件列表接口
  499. @router.post("/list_active")
  500. async def list_active(
  501. request: Request,
  502. db: Session = Depends(get_db)
  503. ):
  504. where = and_(EventBase.del_flag == '0', EventBase.event_title != '', EventBase.event_status.in_(['0', '1']))
  505. rows = db.query(EventBase).filter(where).order_by(EventBase.event_time.desc()).all()
  506. data = [
  507. {
  508. "event_id": row.event_code,
  509. "event_title": row.event_title,
  510. "event_type": row.event_type,
  511. "event_level": row.event_level,
  512. "event_status": row.event_status,
  513. "latitude": row.latitude,
  514. "longitude": row.longitude,
  515. "address": row.address,
  516. "event_time": get_datetime_str(row.event_time),
  517. "create_time": get_datetime_str(row.create_time)
  518. }
  519. for row in rows
  520. ]
  521. # 返回结果
  522. return {
  523. "code": 200,
  524. "msg": "查询成功",
  525. "data": data
  526. }
  527. # 将临时事件绑定成正式事件
  528. @router.post("/update_event_id")
  529. async def update_event_id(
  530. request: Request,
  531. body = Depends(remove_xss_json),
  532. db: Session = Depends(get_db)
  533. ):
  534. temp_event_id = body['temp_event_id'] # 临时事件ID
  535. event_id = body['event_id'] # 正式(未开始指挥)事件ID
  536. row = db.query(EventBase).filter(EventBase.event_code == event_id, EventBase.event_status == "0").first()
  537. if row is not None:
  538. info = get_model_dict(row)
  539. row = db.query(EventBase).filter(and_(EventBase.event_code == temp_event_id)).first()
  540. if row is not None:
  541. # 目前只是改变名称和事发地址
  542. row.event_title = info['event_title']
  543. row.del_flag = '0' # 正式事件
  544. if row.address == "":
  545. row.address = info['address']
  546. row.longitude = info['longitude']
  547. row.latitude = info['latitude']
  548. db.commit()
  549. # 把之前的事件ID改为已删除
  550. db.query(EventBase).filter(EventBase.event_code == event_id).update({"del_flag": "2"})
  551. db.commit()
  552. # 返回当前事件信息
  553. row = db.query(EventBase).filter(EventBase.event_code == temp_event_id).first()
  554. data = {
  555. "event_id": row.event_code,
  556. "event_title": row.event_title,
  557. "event_type": row.event_type,
  558. "event_level": row.event_level,
  559. "event_status": row.event_status,
  560. "latitude": row.latitude,
  561. "longitude": row.longitude,
  562. "address": row.address,
  563. "event_time": get_datetime_str(row.event_time),
  564. "create_time": get_datetime_str(row.create_time)
  565. }
  566. return {
  567. "code": 200,
  568. "msg": "绑定成功",
  569. "data": data
  570. }
  571. return {
  572. "code": 500,
  573. "msg": "查询错误,事件不存在"
  574. }
  575. # 登记事发地点
  576. @router.post("/save_address")
  577. async def list_registered(
  578. request: Request,
  579. body = Depends(remove_xss_json),
  580. db: Session = Depends(get_db)
  581. ):
  582. eventId = body['eventId']
  583. row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  584. if row is None:
  585. return {
  586. "code": 500,
  587. "msg": "事件编号不存在"
  588. }
  589. row.address = body['address']
  590. row.longitude = body['longitude']
  591. row.latitude = body['latitude']
  592. db.commit()
  593. return {
  594. "code": 200,
  595. "msg": "登记事发地点成功"
  596. }
  597. # 匹配预案
  598. @router.post("/march_emergency_plan")
  599. async def martch_emergency_plan(
  600. request: Request,
  601. body = Depends(remove_xss_json),
  602. db: Session = Depends(get_db)
  603. ):
  604. eventId = body['eventId']
  605. row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  606. if row is None or row.event_type == '':
  607. return {
  608. "code": 500,
  609. "msg": "事件编号不正确或事件类型为空"
  610. }
  611. event_type = row.event_type
  612. plan_id = row.plan_id
  613. response_level = row.response_level
  614. # 如果已事件已匹配预案,直接返回
  615. if plan_id != '' and response_level != '':
  616. row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).filter(EmergencyPlan.del_flag == "0").first()
  617. if row is not None:
  618. plan_name = row.plan_name
  619. return {
  620. "code": 200,
  621. "msg": "匹配预案成功",
  622. "data": {
  623. "eventId": eventId,
  624. "plan_id": plan_id,
  625. "plan_name": plan_name,
  626. "response_level": response_level
  627. }
  628. }
  629. '''
  630. 匹配到事件类型
  631. '''
  632. row = db.query(EmergencyPlan).filter(EmergencyPlan.event_type == event_type).filter(EmergencyPlan.del_flag == "0").first()
  633. if row is None:
  634. event_type_text = db_dict.get_dict_label(db, "mm_event_type", event_type)
  635. return {
  636. "code": 500,
  637. "msg": f"无法匹配事件类型{event_type_text}到相应的预案"
  638. }
  639. plan_id = row.plan_number
  640. plan_name = row.plan_name
  641. response_level = row.response_level
  642. return {
  643. "code": 200,
  644. "msg": "匹配预案成功",
  645. "data": {
  646. "eventId": eventId,
  647. "plan_id": plan_id,
  648. "plan_name": plan_name,
  649. "response_level": response_level
  650. }
  651. }
  652. # 取消预案
  653. @router.post("/cancel_emergency_plan")
  654. async def cancel_emergency_plan(
  655. request: Request,
  656. body = Depends(remove_xss_json),
  657. db: Session = Depends(get_db)
  658. ):
  659. eventId = body['eventId']
  660. event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  661. if event_row is None:
  662. return {
  663. "code": 500,
  664. "msg": "事件编号不存在"
  665. }
  666. plan_id = event_row.plan_id
  667. if plan_id != "":
  668. # 清空之前的下发内容
  669. db.query(EventEmergencyNotify).filter(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId)).delete()
  670. db.commit()
  671. event_row.plan_id = ""
  672. event_row.response_level = ""
  673. db.commit()
  674. return {
  675. "code": 200,
  676. "msg": "取消响应成功"
  677. }
  678. #变更响应登记
  679. @router.post("/update_emergency_plan_response_level")
  680. async def update_emergency_plan_response_level(
  681. request: Request,
  682. body = Depends(remove_xss_json),
  683. db: Session = Depends(get_db)
  684. ):
  685. eventId = body['eventId']
  686. plan_id = body['plan_id']
  687. response_level = body['response_level']
  688. event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  689. if event_row is None:
  690. return {
  691. "code": 500,
  692. "msg": "事件编号不存在"
  693. }
  694. plan_row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).first()
  695. if plan_row is None:
  696. return {
  697. "code": 500,
  698. "msg": "预案不存在"
  699. }
  700. # 绑定预案ID和响应等级
  701. event_row.plan_id = plan_row.plan_number
  702. event_row.response_level = response_level
  703. event_row.event_type = plan_row.event_type
  704. event_row.del_flag = "0" # 临时事件改为正式事件
  705. db.commit()
  706. # 清空之前的下发内容
  707. # db.query(EventEmergencyNotify).filter(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId)).delete()
  708. # db.commit()
  709. return {
  710. "code": 200,
  711. "msg": "变更响应登记成功"
  712. }
  713. # 启动预案
  714. @router.post("/lauch_emergency_plan")
  715. async def lauch_emergency_plan(
  716. request: Request,
  717. body = Depends(remove_xss_json),
  718. db: Session = Depends(get_db)
  719. ):
  720. eventId = body['eventId']
  721. plan_id = body['plan_id']
  722. response_level = body['response_level']
  723. event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  724. if event_row is None:
  725. return {
  726. "code": 500,
  727. "msg": "事件编号不存在"
  728. }
  729. '''
  730. if event_row.plan_id != '' and event_row.response_level != '':
  731. return {
  732. "code": 500,
  733. "msg": "预案已启动"
  734. }
  735. '''
  736. plan_row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).first()
  737. if plan_row is None:
  738. return {
  739. "code": 500,
  740. "msg": "预案不存在"
  741. }
  742. # 绑定预案ID和响应等级
  743. event_row.plan_id = plan_row.plan_number
  744. event_row.response_level = response_level
  745. event_row.event_type = plan_row.event_type
  746. event_row.del_flag = "0" # 临时事件改为正式事件
  747. db.commit()
  748. return {
  749. "code": 200,
  750. "msg": "启动预案成功"
  751. }
  752. # 预案任务下发
  753. @router.post("/send_emergency_plan_task_by_yzy")
  754. async def send_emergency_plan_task_by_yzy(
  755. request: Request,
  756. background_tasks: BackgroundTasks,
  757. body = Depends(remove_xss_json),
  758. db: Session = Depends(get_db),
  759. user_id = Depends(valid_access_token)
  760. ):
  761. time.sleep(1.0)
  762. eventId = body['eventId']
  763. tasks = body['tasks']
  764. event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  765. if event_row is None:
  766. return {
  767. "code": 500,
  768. "msg": "事件编号不存在"
  769. }
  770. '''
  771. c1 = db.query(EventEmergencyNotify).filter(EventEmergencyNotify.event_id == eventId).count()
  772. if c1 > 0:
  773. return {
  774. "code": 500,
  775. "msg": "预案任务已下发"
  776. }
  777. '''
  778. event_info = get_model_dict(event_row)
  779. plan_id = event_info['plan_id']
  780. response_level = db_dict.get_dict_label(db, "response_level", event_info['response_level'])
  781. if plan_id is None or plan_id == '':
  782. return {
  783. "code": 500,
  784. "msg": "请先启动预案"
  785. }
  786. row = db.query(EmergencyPlan).filter(EmergencyPlan.plan_number == plan_id).first()
  787. if row is None:
  788. return {
  789. "code": 500,
  790. "msg": "没有匹配的预案"
  791. }
  792. plan_info = get_model_dict(row)
  793. plan_name = plan_info['plan_name']
  794. rows = db.query(EmergencyUnit).filter(EmergencyUnit.plan_id == plan_id).order_by(EmergencyUnit.dept_order.asc()).all()
  795. if len(rows) == 0:
  796. return {
  797. "code": 500,
  798. "msg": "该预案没有相关通知部门"
  799. }
  800. # 清空之前的下发内容
  801. db.query(EventEmergencyNotify).filter(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId)).delete()
  802. db.commit()
  803. for row in rows:
  804. dept_id = row.dept_id
  805. dept_name = row.dept_name
  806. leader_content = ""
  807. if str(dept_id) in tasks:
  808. leader_content = tasks[str(dept_id)]
  809. # 已下发的过滤掉,避免重发
  810. '''
  811. row_exists = db.query(EventEmergencyNotify).filter(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId, EventEmergencyNotify.dept_id == dept_id)).first()
  812. if row_exists is not None:
  813. continue
  814. '''
  815. if leader_content != "":
  816. # 领导批示
  817. new_instruction = TaskLeaderInstructions(
  818. event_code = eventId,
  819. dept_id = dept_id,
  820. dept_name = dept_name,
  821. content = leader_content,
  822. create_time = datetime.now(),
  823. recorded_by = user_id
  824. )
  825. db.add(new_instruction)
  826. db.commit()
  827. # 通过预案人员管理匹配负责人
  828. _user_id = 0
  829. user_name = ''
  830. contact_row = db.query(EmergencyContactInfo).filter(and_(EmergencyContactInfo.del_flag == "0", EmergencyContactInfo.unit_id == dept_id)).first()
  831. if contact_row is None:
  832. continue
  833. yzy_account = mpfun.dec_data(contact_row.yue_gov_ease_phone)
  834. nick_name = contact_row.contact_name
  835. yzy_user_row = db.query(YzyOrgUserEntity).filter(YzyOrgUserEntity.account == yzy_account).first()
  836. if yzy_user_row is None:
  837. logger.info("粤政易人员ID不存在", yzy_account)
  838. yzy_user_id = ""
  839. else:
  840. yzy_user_id = yzy_user_row.userid
  841. # 通过通讯录匹配相关负责人
  842. # user_row = db.query(SysUser).filter(SysUser.user_id == 1).first()
  843. # user_id = user_row.user_id
  844. # user_name = user_row.user_name
  845. # nick_name = user_row.nick_name
  846. # yzy_user_id = "eb4kehgy6wj4qn0jhx1dk6" # 暂时写死梦梅的账号
  847. yzy_content = "{},您好!《{}》现已全面启动,特此通知您单位迅速响应,全力做好预案工作要点:{}".format(row.dept_name, plan_info['plan_name'], row.content)
  848. event_emergency_notify = EventEmergencyNotify(
  849. event_id = eventId,
  850. plan_id = plan_id,
  851. dept_id = dept_id,
  852. dept_name = dept_name,
  853. user_id = _user_id,
  854. user_name = user_name,
  855. nick_name = nick_name,
  856. yzy_user_id = yzy_user_id,
  857. yzy_content = yzy_content,
  858. sent_time = datetime.now(),
  859. sent_status = 0,
  860. comment = leader_content # 领导批示
  861. )
  862. db.add(event_emergency_notify)
  863. db.commit()
  864. db.refresh(event_emergency_notify)
  865. # 发送粤政易消息
  866. detail_url = "{}{}{}".format(settings.YZY_WEB_ROOT, "/yjxp/#/event/detail?event_id=", eventId)
  867. description = "预案名称: " + plan_name + "\n响应级别:" + response_level + "\n消息内容: "+yzy_content
  868. data = {
  869. "yzy_userid": yzy_user_id,
  870. "mobile": yzy_account,
  871. "content": description,
  872. "recorded_by": user_id,
  873. "detail_url": detail_url,
  874. "foreign_key": event_emergency_notify.id,
  875. "from_scenario": "event_emergency_notify",
  876. "title": "预案通知"
  877. }
  878. YzyApi.add_to_msg_queue(db, data)
  879. db_msg_center.add_message(db, "预案通知", _user_id, f"{plan_name}{response_level}通知", yzy_content, event_emergency_notify.id, "event_emergency_notify")
  880. return {
  881. "code": 200,
  882. "msg": "预案任务下发成功"
  883. }
  884. '''
  885. def async_send_yzy_msg(db: Session, queue: dict):
  886. for item in queue:
  887. event_emergency_notify = db.query(EventEmergencyNotify).filter(EventEmergencyNotify.id == item['id']).first()
  888. if event_emergency_notify is not None and event_emergency_notify.sent_status == 0:
  889. yzy_user_id = item['yzy_user_id']
  890. if yzy_user_id == "":
  891. event_emergency_notify.sent_status = 9 # 发送失败
  892. db.commit()
  893. else:
  894. description = item['description']
  895. detail_url = item['detail_url']
  896. try:
  897. resp = YzyApi.send_textcard_message([yzy_user_id], "预案响应消息", description, detail_url)
  898. if resp['errcode'] == 0:
  899. event_emergency_notify.sent_status = 1 # 发送成功
  900. else:
  901. event_emergency_notify.sent_status = 9 # 发送失败
  902. db.commit()
  903. except Exception:
  904. pass
  905. '''
  906. # 获取预案通知
  907. @router.post("/emergency_plan_task_list")
  908. async def emergency_plan_task_list(
  909. request: Request,
  910. body = Depends(remove_xss_json),
  911. db: Session = Depends(get_db)
  912. ):
  913. eventId = body['eventId']
  914. event_row = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  915. if event_row is None:
  916. return {
  917. "code": 500,
  918. "msg": "事件编号不存在"
  919. }
  920. event_info = get_model_dict(event_row)
  921. plan_id = event_info['plan_id']
  922. if plan_id is None or plan_id == '':
  923. return {
  924. "code": 200,
  925. "msg": "未关联预案",
  926. "data": []
  927. }
  928. where = and_(and_(EventEmergencyNotify.plan_id == plan_id, EventEmergencyNotify.event_id == eventId))
  929. rows = db.query(EventEmergencyNotify).filter(where).order_by(EventEmergencyNotify.id.asc()).all()
  930. data = [
  931. {
  932. "dept_name": row.dept_name,
  933. "sent_time": get_datetime_str(row.sent_time),
  934. "sent_status": row.sent_status,
  935. "sent_status_text": get_sent_status_text(row.sent_status),
  936. "yzy_content": row.yzy_content,
  937. "nick_name": row.nick_name,
  938. "comment": row.comment,
  939. "leaders": get_event_leaders(db, eventId, row.dept_id)
  940. }
  941. for row in rows
  942. ]
  943. # 返回结果
  944. return {
  945. "code": 200,
  946. "msg": "查询成功",
  947. "data": data
  948. }
  949. def get_event_leaders(db: Session, event_id: str, dept_id: int) -> dict:
  950. rows = db.query(EventLeaderUser).filter(and_(EventLeaderUser.del_flag == '0', EventLeaderUser.event_id == event_id, EventLeaderUser.unit_id == dept_id)).order_by(EventLeaderUser.create_time.asc()).all()
  951. return [
  952. {
  953. "user_type": row.user_type,
  954. "user_name": row.user_name,
  955. "mobile": row.mobile
  956. }
  957. for row in rows
  958. ]
  959. def get_sent_status_text(sent_status) -> str:
  960. if sent_status == 0:
  961. return '暂未发送'
  962. elif sent_status == 1:
  963. return '发送成功'
  964. elif sent_status == 0:
  965. return '发送失败'
  966. else:
  967. return str(sent_status)
  968. # 上报伤亡情况
  969. @router.post("/upload_casualties")
  970. async def upload_casualties(
  971. request: Request,
  972. body = Depends(remove_xss_json),
  973. db: Session = Depends(get_db)
  974. ):
  975. fileNames = []
  976. eventId = body['event_id']
  977. if 'fileNames' in body:
  978. fileNames = body['fileNames']
  979. del body['fileNames']
  980. del body['event_id']
  981. # 标记已上传
  982. body['casualties'] = '1'
  983. db.query(EventBase).filter(EventBase.event_code == eventId).update(body)
  984. db.commit()
  985. if len(fileNames) > 0:
  986. event_base = db.query(EventBase).filter(EventBase.event_code == eventId).first()
  987. # 删除之前的总结报告,保留当前这一份
  988. db.query(EventFile).filter(and_(EventFile.from_scenario == 'event_summary_file', EventFile.foreign_key == event_base.event_code)).update({"del_flag": "2"})
  989. db.commit()
  990. event_files = [
  991. EventFile(
  992. event_id=event_base.id,
  993. file_name=fileName["name"], # 使用 fileName["name"] 作为文件名
  994. file_path=f'/data/upload/mergefile/uploads/{fileName["url"]}',
  995. file_size=os.path.getsize(f'/data/upload/mergefile/uploads/{fileName["url"]}'),
  996. storage_file_name=fileName["url"],
  997. foreign_key=event_base.event_code,
  998. from_scenario="event_summary_file",
  999. update_time=datetime.now(),
  1000. create_time=datetime.now(),
  1001. del_flag='0'
  1002. )
  1003. for fileName in fileNames # body['fileNames'] 现在是一个包含对象的数组,每个对象都有 'name' 和 'url' 属性
  1004. ]
  1005. db.add_all(event_files)
  1006. db.commit()
  1007. return {
  1008. "code": 200,
  1009. "msg": "保存事件伤亡情况成功"
  1010. }