call.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends, Query, HTTPException
  4. from fastapi.responses import FileResponse, StreamingResponse
  5. from database import get_db
  6. from sqlalchemy import text, exists, and_, or_, not_
  7. from sqlalchemy.orm import Session
  8. from sqlalchemy.sql import func
  9. from models import *
  10. import uuid
  11. import os
  12. from sqlalchemy import create_engine, select
  13. from typing import Optional
  14. from utils.StripTagsHTMLParser import *
  15. from common.db import db_user, db_yzy, db_dept, db_msg_center
  16. from common.security import valid_access_token
  17. import traceback
  18. from utils import *
  19. from datetime import datetime, timedelta
  20. from common import YzyApi
  21. from common.db import db_dict
  22. from urllib.parse import quote
  23. import base64
  24. from config import settings
  25. from exceptions import AppException
  26. from typing import List, Dict,Set
  27. import openpyxl
  28. from io import BytesIO
  29. from PIL import Image
  30. from common.enc import mpfun
  31. router = APIRouter()
  32. @router.get("/dept_by_key", response_model=Dict)
  33. def dept_by_key(db: Session = Depends(get_db), area_code: str = Query(None), keyword: str = Query(None)):
  34. def get_dept_id_by_area_code(db: Session, area_code: str):
  35. dept = db.query(EmergencyContactDepartment). \
  36. filter(and_(EmergencyContactDepartment.del_flag == '0', EmergencyContactDepartment.area_code == area_code)). \
  37. order_by(EmergencyContactDepartment.display_order.asc()).first()
  38. if dept is None:
  39. return 0
  40. else:
  41. return dept.id
  42. def get_dept_tree(db: Session, dept_id: int):
  43. dept = db.query(EmergencyContactDepartment). \
  44. filter(and_(EmergencyContactDepartment.del_flag == '0', EmergencyContactDepartment.id == dept_id)).first()
  45. if not dept:
  46. return None
  47. children = []
  48. for child in db.query(EmergencyContactDepartment).filter(and_(EmergencyContactDepartment.del_flag == '0', EmergencyContactDepartment.parent_department_id == dept.id)).all():
  49. child = get_dept_tree(db, child.id)
  50. if child is not None:
  51. children.append(child)
  52. dept_info = {
  53. "uuid":str(uuid.uuid4()).replace('-',''),
  54. "id": dept.id,
  55. "label": dept.department_name,
  56. "deptType": True
  57. }
  58. if len(children) > 0:
  59. dept_info["children"] = children
  60. return dept_info
  61. dept_id = get_dept_id_by_area_code(db, area_code)
  62. if dept_id == 0:
  63. return {
  64. "code": 200,
  65. "msg": "成功",
  66. "data": []
  67. }
  68. print('dept_id:', dept_id)
  69. data = get_dept_tree(db, dept_id)
  70. return {
  71. "code": 200,
  72. "msg": "成功",
  73. "data": [data]
  74. }
  75. # 一键点名全市至区县
  76. @router.post("/create_by_city_to_area")
  77. async def create_by_city_to_area(
  78. db: Session = Depends(get_db),
  79. user_id = Depends(valid_access_token)
  80. ):
  81. current_day = get_date_str(datetime.now().date())
  82. current_time = get_datetime_str(datetime.now())
  83. try:
  84. # 过滤当前时间内的值班人员
  85. sql = f"""
  86. select p.duty_id, d.id as dept_id, d.department_name as dept_name from tp_duty_schedule s, tp_duty_personnel_arrangement p, tp_emergency_contact_user u, tp_emergency_contact_department d
  87. where s.id = p.duty_id and p.personnel_id= u.id and u.department_id = d.id
  88. and s.del_flag = '0' and p.del_flag = '0' and u.del_flag = '0' and d.del_flag = '0'
  89. and p.position_id = 1 and s.start_time > '{current_day}' and s.start_time < '{current_time}' and s.end_time > '{current_time}'
  90. and length(d.area_code) <= 6
  91. """
  92. print(sql)
  93. rows = db.execute(text(sql)).fetchall()
  94. user_count = len(rows)
  95. if user_count == 0:
  96. raise AppException(500, "暂无相关值班人员信息")
  97. new_call = OnlineRollCallBase(
  98. call_type = 1,
  99. recorded_by = user_id,
  100. create_time = datetime.now(),
  101. del_flag = '0',
  102. call_status = 1,
  103. user_count = user_count,
  104. ack_count = 0,
  105. unack_count = user_count,
  106. remark = '',
  107. update_time = datetime.now()
  108. )
  109. db.add(new_call)
  110. db.commit()
  111. db.refresh(new_call)
  112. new_call_id = new_call.id
  113. dept_list = []
  114. for row in rows:
  115. shift_id = row['duty_id']
  116. shift_dept_id = row['dept_id']
  117. shift_dept_name = row['dept_name']
  118. arr_rows = db.query(DutyPersonnelArrangement).filter(and_(DutyPersonnelArrangement.duty_id == shift_id, DutyPersonnelArrangement.del_flag == '0')).order_by(DutyPersonnelArrangement.position_id.asc()).all()
  119. leader_id = 0
  120. primary_staff_id = 0
  121. secondary_staff_id = 0
  122. standby_staff_id = 0
  123. i = 0
  124. for arr_item in arr_rows:
  125. if i == 0:
  126. leader_id = arr_item.personnel_id
  127. elif i == 1:
  128. primary_staff_id = arr_item.personnel_id
  129. elif i == 2:
  130. secondary_staff_id = arr_item.personnel_id
  131. elif i == 3:
  132. standby_staff_id = arr_item.personnel_id
  133. i = i + 1
  134. onduty_user = get_emergency_contact_user_name(db, primary_staff_id)
  135. onduty_leader = get_emergency_contact_user_name(db, leader_id)
  136. secondary_staff_user = get_emergency_contact_user_name(db, secondary_staff_id)
  137. standby_staff_user = get_emergency_contact_user_name(db, standby_staff_id)
  138. video_url = "#"
  139. call_url = "#"
  140. # 避免同一个部门重复
  141. if shift_dept_id in dept_list:
  142. continue
  143. dept_list.append(shift_dept_id)
  144. new_detail = OnlineRollCallDetail(
  145. pid = new_call_id,
  146. shift_id = shift_id,
  147. dept_id = shift_dept_id,
  148. dept_name = shift_dept_name,
  149. onduty_user = onduty_user,
  150. onduty_leader = onduty_leader,
  151. video_url = video_url,
  152. call_url = call_url,
  153. ack_status = 0,
  154. ack_time = None,
  155. create_time = datetime.now(),
  156. del_flag = '0',
  157. ack_type = 0,
  158. leader_id = leader_id,
  159. primary_staff_id = primary_staff_id,
  160. secondary_staff_id = secondary_staff_id,
  161. standby_staff_id = standby_staff_id,
  162. secondary_staff_user = secondary_staff_user,
  163. standby_staff_user = standby_staff_user
  164. )
  165. db.add(new_detail)
  166. db.commit()
  167. db.refresh(new_detail)
  168. # 发送粤政易消息
  169. send_yzy_msg(db, new_detail, user_id)
  170. return {
  171. "code": 200,
  172. "msg": "点名创建成功",
  173. "data": new_call_id
  174. }
  175. except AppException as e:
  176. return {
  177. "code": e.code,
  178. "msg": e.msg
  179. }
  180. except Exception as e:
  181. traceback.print_exc()
  182. # 处理异常
  183. raise HTTPException(status_code=500, detail=str(e))
  184. def get_nick_name_by_id(db: Session, uid: int):
  185. row = db.query(EmergencyContactUser).filter(and_(EmergencyContactUser.id == uid, EmergencyContactUser.del_flag == '0')).first()
  186. if row is not None:
  187. return row.name
  188. return '-'
  189. # 一键点名全市至镇街
  190. @router.post("/create_by_city_to_district")
  191. async def create_by_city_to_district(
  192. db: Session = Depends(get_db),
  193. user_id = Depends(valid_access_token)
  194. ):
  195. current_day = get_date_str(datetime.now().date())
  196. current_time = get_datetime_str(datetime.now())
  197. try:
  198. # 过滤当前时间内的值班人员
  199. sql = f"""
  200. select p.duty_id, d.id as dept_id, d.department_name as dept_name from tp_duty_schedule s, tp_duty_personnel_arrangement p, tp_emergency_contact_user u, tp_emergency_contact_department d
  201. where s.id = p.duty_id and p.personnel_id= u.id and u.department_id = d.id
  202. and s.del_flag = '0' and p.del_flag = '0' and u.del_flag = '0' and d.del_flag = '0'
  203. and p.position_id = 1 and s.start_time > '{current_day}' and s.start_time < '{current_time}' and s.end_time > '{current_time}'
  204. and length(d.area_code) <= 9
  205. """
  206. print(sql)
  207. rows = db.execute(text(sql)).fetchall()
  208. user_count = len(rows)
  209. if user_count == 0:
  210. raise AppException(500, "暂无相关值班人员信息")
  211. new_call = OnlineRollCallBase(
  212. call_type = 1,
  213. recorded_by = user_id,
  214. create_time = datetime.now(),
  215. del_flag = '0',
  216. call_status = 1,
  217. user_count = user_count,
  218. ack_count = 0,
  219. unack_count = user_count,
  220. remark = '',
  221. update_time = datetime.now()
  222. )
  223. db.add(new_call)
  224. db.commit()
  225. db.refresh(new_call)
  226. new_call_id = new_call.id
  227. dept_list = []
  228. for row in rows:
  229. shift_id = row['duty_id']
  230. shift_dept_id = row['dept_id']
  231. shift_dept_name = row['dept_name']
  232. arr_rows = db.query(DutyPersonnelArrangement).filter(and_(DutyPersonnelArrangement.duty_id == shift_id, DutyPersonnelArrangement.del_flag == '0')).order_by(DutyPersonnelArrangement.position_id.asc()).all()
  233. leader_id = 0
  234. primary_staff_id = 0
  235. secondary_staff_id = 0
  236. standby_staff_id = 0
  237. i = 0
  238. for arr_item in arr_rows:
  239. if i == 0:
  240. leader_id = arr_item.personnel_id
  241. elif i == 1:
  242. primary_staff_id = arr_item.personnel_id
  243. elif i == 2:
  244. secondary_staff_id = arr_item.personnel_id
  245. elif i == 3:
  246. standby_staff_id = arr_item.personnel_id
  247. i = i + 1
  248. onduty_user = get_emergency_contact_user_name(db, primary_staff_id)
  249. onduty_leader = get_emergency_contact_user_name(db, leader_id)
  250. secondary_staff_user = get_emergency_contact_user_name(db, secondary_staff_id)
  251. standby_staff_user = get_emergency_contact_user_name(db, standby_staff_id)
  252. video_url = "#"
  253. call_url = "#"
  254. # 避免同一个部门重复
  255. if shift_dept_id in dept_list:
  256. continue
  257. dept_list.append(shift_dept_id)
  258. new_detail = OnlineRollCallDetail(
  259. pid = new_call_id,
  260. shift_id = shift_id,
  261. dept_id = shift_dept_id,
  262. dept_name = shift_dept_name,
  263. onduty_user = onduty_user,
  264. onduty_leader = onduty_leader,
  265. video_url = video_url,
  266. call_url = call_url,
  267. ack_status = 0,
  268. ack_time = None,
  269. create_time = datetime.now(),
  270. del_flag = '0',
  271. ack_type = 0,
  272. leader_id = leader_id,
  273. primary_staff_id = primary_staff_id,
  274. secondary_staff_id = secondary_staff_id,
  275. standby_staff_id = standby_staff_id,
  276. secondary_staff_user = secondary_staff_user,
  277. standby_staff_user = standby_staff_user
  278. )
  279. db.add(new_detail)
  280. db.commit()
  281. db.refresh(new_detail)
  282. # 发送粤政易消息
  283. send_yzy_msg(db, new_detail, user_id)
  284. return {
  285. "code": 200,
  286. "msg": "点名创建成功",
  287. "data": new_call_id
  288. }
  289. except AppException as e:
  290. return {
  291. "code": e.code,
  292. "msg": e.msg
  293. }
  294. except Exception as e:
  295. traceback.print_exc()
  296. # 处理异常
  297. raise HTTPException(status_code=500, detail=str(e))
  298. # 新建点名(分区/县点名)
  299. @router.post("/create_by_dept_ids")
  300. async def create_by_dept_ids(
  301. db: Session = Depends(get_db),
  302. body = Depends(remove_xss_json),
  303. user_id = Depends(valid_access_token)
  304. ):
  305. current_day = get_date_str(datetime.now().date())
  306. current_time = datetime.now().time()
  307. try:
  308. if len(body['depts']) == 0:
  309. raise AppException(500, "请勾选部门")
  310. new_call = OnlineRollCallBase(
  311. call_type = 3,
  312. recorded_by = user_id,
  313. create_time = datetime.now(),
  314. del_flag = '0',
  315. call_status = 1,
  316. user_count = 0,
  317. ack_count = 0,
  318. unack_count = 0,
  319. remark = body['remark'],
  320. update_time = datetime.now()
  321. )
  322. db.add(new_call)
  323. db.commit()
  324. db.refresh(new_call)
  325. new_call_id = new_call.id
  326. for dept_id in body['depts']:
  327. # 过滤当前时间内的值班人员
  328. sql = f"""
  329. select p.duty_id, d.id as dept_id, d.department_name as dept_name from tp_duty_schedule s, tp_duty_personnel_arrangement p, tp_emergency_contact_user u, tp_emergency_contact_department d
  330. where s.id = p.duty_id and p.personnel_id= u.id and u.department_id = d.id
  331. and s.del_flag = '0' and p.del_flag = '0' and u.del_flag = '0' and d.del_flag = '0'
  332. and p.position_id = 1 and s.start_time > '{current_day}' and s.start_time < '{current_time}' and s.end_time > '{current_time}'
  333. and d.id = {dept_id}
  334. """
  335. print(sql)
  336. row = db.execute(text(sql)).fetchone()
  337. if row is not None:
  338. shift_id = row['duty_id']
  339. shift_dept_id = row['dept_id']
  340. shift_dept_name = row['dept_name']
  341. arr_rows = db.query(DutyPersonnelArrangement).filter(and_(DutyPersonnelArrangement.duty_id == shift_id, DutyPersonnelArrangement.del_flag == '0')).order_by(DutyPersonnelArrangement.position_id.asc()).all()
  342. leader_id = 0
  343. primary_staff_id = 0
  344. secondary_staff_id = 0
  345. standby_staff_id = 0
  346. i = 0
  347. for arr_item in arr_rows:
  348. if i == 0:
  349. leader_id = arr_item.personnel_id
  350. elif i == 1:
  351. primary_staff_id = arr_item.personnel_id
  352. elif i == 2:
  353. secondary_staff_id = arr_item.personnel_id
  354. elif i == 3:
  355. standby_staff_id = arr_item.personnel_id
  356. i = i + 1
  357. onduty_user = get_emergency_contact_user_name(db, primary_staff_id)
  358. onduty_leader = get_emergency_contact_user_name(db, leader_id)
  359. secondary_staff_user = get_emergency_contact_user_name(db, secondary_staff_id)
  360. standby_staff_user = get_emergency_contact_user_name(db, standby_staff_id)
  361. video_url = "#"
  362. call_url = "#"
  363. new_detail = OnlineRollCallDetail(
  364. pid = new_call_id,
  365. shift_id = shift_id,
  366. dept_id = shift_dept_id,
  367. dept_name = shift_dept_name,
  368. onduty_user = onduty_user,
  369. onduty_leader = onduty_leader,
  370. video_url = video_url,
  371. call_url = call_url,
  372. ack_status = 0,
  373. ack_time = None,
  374. create_time = datetime.now(),
  375. del_flag = '0',
  376. ack_type = 0,
  377. leader_id = leader_id,
  378. primary_staff_id = primary_staff_id,
  379. secondary_staff_id = secondary_staff_id,
  380. standby_staff_id = standby_staff_id,
  381. secondary_staff_user = secondary_staff_user,
  382. standby_staff_user = standby_staff_user
  383. )
  384. db.add(new_detail)
  385. db.commit()
  386. # 发送粤政易消息
  387. send_yzy_msg(db, new_detail, user_id)
  388. # 检查多次,避免人员为空
  389. user_count = db.query(OnlineRollCallDetail).filter(OnlineRollCallDetail.pid == new_call_id).count()
  390. if user_count == 0:
  391. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == new_call_id).delete()
  392. db.commit()
  393. raise AppException(500, "暂无相关值班人员信息")
  394. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == new_call_id).update({"user_count": user_count, "unack_count": user_count})
  395. db.commit()
  396. return {
  397. "code": 200,
  398. "msg": "点名创建成功",
  399. "data": new_call_id
  400. }
  401. except AppException as e:
  402. return {
  403. "code": e.code,
  404. "msg": e.msg
  405. }
  406. except Exception as e:
  407. traceback.print_exc()
  408. # 处理异常
  409. raise HTTPException(status_code=500, detail=str(e))
  410. def get_emergency_contact_user_name(db: Session, uid: int) -> str:
  411. row = db.query(EmergencyContactUser).filter(EmergencyContactUser.id == uid).first()
  412. if row is not None:
  413. return row.name
  414. else:
  415. return ''
  416. # 结束点名
  417. @router.post("/end")
  418. async def end_call(
  419. db: Session = Depends(get_db),
  420. body = Depends(remove_xss_json),
  421. user_id = Depends(valid_access_token)
  422. ):
  423. call_id = body['call_id']
  424. row = db.query(OnlineRollCallBase).filter(and_(OnlineRollCallBase.id == call_id, OnlineRollCallBase.del_flag == '0')).first()
  425. if row is None:
  426. return {
  427. "code": 500,
  428. "msg": "点名记录不存在"
  429. }
  430. if row.call_status != 1:
  431. return {
  432. "code": 500,
  433. "msg": "点名记录状态已结束"
  434. }
  435. row.end_time = datetime.now()
  436. row.call_status = 2 # 结束
  437. row.update_time = datetime.now()
  438. db.commit()
  439. return {
  440. "code": 200,
  441. "msg": "点名结束成功"
  442. }
  443. # 标记用户已应答
  444. @router.post("/ack")
  445. async def ack_all(
  446. db: Session = Depends(get_db),
  447. body = Depends(remove_xss_json),
  448. user_id = Depends(valid_access_token)
  449. ):
  450. call_id = get_req_param(body, 'call_id')
  451. base64_data = get_req_param(body, "photo_data")
  452. file_name = new_guid() + ".png"
  453. file_path = f'/data/upload/mergefile/uploads/{file_name}'
  454. base64_data = base64_data.replace("data:image/png;base64,", "")
  455. binary_data = base64.b64decode(base64_data)
  456. bytes_io = BytesIO(binary_data)
  457. image = Image.open(bytes_io)
  458. image.save(file_path)
  459. base_row = db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).first()
  460. if base_row is None:
  461. return {
  462. "code": 500,
  463. "msg": "点名记录不存在"
  464. }
  465. user_or_where = or_(OnlineRollCallDetail.leader_id == user_id, OnlineRollCallDetail.primary_staff_id == user_id, OnlineRollCallDetail.secondary_staff_id == user_id, OnlineRollCallDetail.standby_staff_id == user_id)
  466. detail_row = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, user_or_where)).first()
  467. if detail_row is None:
  468. return {
  469. "code": 500,
  470. "msg": "点名记录不存在!"
  471. }
  472. new_file = OnlineRollCallFile(
  473. file_name=f"点名头像{user_id}.png",
  474. storage_file_name=file_name,
  475. file_path=f'/data/upload/mergefile/uploads/{file_name}',
  476. file_size=os.path.getsize(f'/data/upload/mergefile/uploads/{file_name}'),
  477. foreign_key=str(detail_row.id),
  478. from_scenario="online_call_photo_file",
  479. update_time=datetime.now(),
  480. create_time=datetime.now(),
  481. create_by=user_id,
  482. create_dept=0,
  483. del_flag='0',
  484. status=0,
  485. )
  486. db.add(new_file)
  487. detail_row.ack_status = 1 # 已应答
  488. detail_row.ack_time = datetime.now()
  489. db.commit()
  490. logger.info("标记[在线点名]已读 {}", str(detail_row.id))
  491. db_msg_center.update_msg_read(db, user_id, "在线点名", str(detail_row.id))
  492. # 统计应答数
  493. ack_count = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.ack_status == 1)).count()
  494. # 统计未应答数
  495. unack_count = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.ack_status == 2)).count()
  496. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).update({
  497. "ack_count": ack_count, "unack_count": unack_count, "update_time": datetime.now()
  498. })
  499. db.commit()
  500. return {
  501. "code": 200,
  502. "msg": "应答成功"
  503. }
  504. # 查询是否有我的待应答记录(提醒)
  505. @router.post("/mycall")
  506. async def query_mycall(
  507. db: Session = Depends(get_db),
  508. user_id = Depends(valid_access_token)
  509. ):
  510. is_myid_where = or_(OnlineRollCallDetail.standby_staff_id == user_id,
  511. OnlineRollCallDetail.leader_id == user_id,
  512. OnlineRollCallDetail.primary_staff_id == user_id,
  513. OnlineRollCallDetail.secondary_staff_id == user_id)
  514. rows = db.query(OnlineRollCallDetail).filter(and_(is_myid_where, OnlineRollCallDetail.ack_status == 0)).all()
  515. data = []
  516. for row in rows:
  517. call_id = row.pid
  518. base_row = db.query(OnlineRollCallBase).filter(and_(OnlineRollCallBase.id == call_id, OnlineRollCallBase.call_status == 1, OnlineRollCallBase.del_flag == '0')).first()
  519. if base_row is not None:
  520. data.append({
  521. "id": call_id,
  522. "time1": get_datetime_str(base_row.create_time)
  523. })
  524. return {
  525. "code": 200,
  526. "msg": "查询成功",
  527. "data": data,
  528. "total": len(data)
  529. }
  530. #应答详情
  531. @router.get('/detail')
  532. async def get_event_detail(
  533. request: Request,
  534. call_id: str = Query(None, description='点名ID'),
  535. db: Session = Depends(get_db)):
  536. try:
  537. base_row = db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).first()
  538. if base_row is None:
  539. return {
  540. "code": 500,
  541. "msg": "点名记录不存在"
  542. }
  543. data = get_model_dict(base_row)
  544. data['begin_time'] = get_datetime_str(data['create_time'])
  545. data['update_time'] = get_datetime_str(data['update_time'])
  546. data['duration_time'] = ''
  547. # 已应答(结束)
  548. if data['call_status'] == 2:
  549. # 处理垃圾数据
  550. if base_row.end_time is None:
  551. base_row.end_time = datetime.now()
  552. db.commit()
  553. time_diff = base_row.end_time - base_row.create_time
  554. # hours,minutes,seconds = str(time_diff).split(':')
  555. data['duration_time'] = str(time_diff)
  556. detail_rows = db.query(OnlineRollCallDetail).filter(OnlineRollCallDetail.pid == call_id).all()
  557. items = []
  558. for row in detail_rows:
  559. detail_info = get_model_dict(row)
  560. detail_info['begin_time'] = get_datetime_str(detail_info['create_time'])
  561. detail_info['ack_time'] = get_datetime_str(detail_info['ack_time'])
  562. detail_info['ack_status_text'] = get_ack_status_text(detail_info['ack_status'])
  563. items.append(detail_info)
  564. data['items'] = items
  565. return {
  566. "code": 200,
  567. "msg": "查询成功",
  568. "data": data
  569. }
  570. except Exception as e:
  571. # 处理异常
  572. traceback.print_exc()
  573. raise HTTPException(status_code=500, detail=str(e))
  574. def get_yzy_userid_by_uid(db: Session, uid: int):
  575. row = db.query(EmergencyContactUser).filter(and_(EmergencyContactUser.id == uid, EmergencyContactUser.del_flag == '0')).first()
  576. if row is not None:
  577. return row.mobile_phone, row.userid
  578. return None
  579. # 发送粤政易消息
  580. def send_yzy_msg(db: Session, detail_entity: OnlineRollCallDetail, user_id: int) -> None:
  581. to_users = [detail_entity.leader_id, detail_entity.primary_staff_id, detail_entity.secondary_staff_id, detail_entity.standby_staff_id]
  582. user_list = []
  583. for to_user_id in to_users:
  584. user_info = db.query(EmergencyContactUser).filter(and_(EmergencyContactUser.id == to_user_id, EmergencyContactUser.del_flag == '0')).first()
  585. if user_info is None:
  586. continue
  587. mobile = user_info.mobile_phone
  588. yzy_userid = user_info.userid
  589. if yzy_userid not in user_list:
  590. create_time = get_datetime_str(detail_entity.create_time)
  591. detail_url = "{}{}".format(settings.YZY_WEB_ROOT, "/yjxp/")
  592. description = f"你有一条在线点名通知,请尽快确认\n点名时间:{create_time}"
  593. data = {
  594. "yzy_userid": yzy_userid,
  595. "mobile": mobile,
  596. "content": description,
  597. "recorded_by": user_id,
  598. "detail_url": detail_url,
  599. "foreign_key": detail_entity.id,
  600. "from_scenario": "online_roll_call_detail",
  601. "title": "在线点名提醒"
  602. }
  603. YzyApi.add_to_msg_queue(db, data)
  604. # 匹配到sys_user的user_id
  605. sys_user_userid = db_user.get_user_id_by_yzyaccount(db, yzy_userid)
  606. db_msg_center.add_message(db, "在线点名", sys_user_userid, "在线点名提醒", "你有一条在线点名通知,请尽快确认", str(detail_entity.id), 'online_roll_call_detail')
  607. user_list.append(yzy_userid)
  608. def get_ack_status_text(ack_status: int) -> str:
  609. if ack_status == 0:
  610. return '未应答'
  611. elif ack_status == 1:
  612. return '已接通'
  613. elif ack_status == 2:
  614. return '呼叫中'
  615. else:
  616. return str(ack_status)
  617. #应答详情
  618. @router.get('/list')
  619. async def get_event_list(
  620. request: Request,
  621. begin_date: str = Query('', description='开始时间'),
  622. end_date: str = Query('', description='结束时间'),
  623. page: int = Query(1, gt=0, description='页码'),
  624. page_size: int = Query(10, gt=0, description='pageSize'),
  625. db: Session = Depends(get_db)):
  626. try:
  627. # 两周内
  628. d1 = datetime.now() - timedelta(days=14)
  629. where = and_(OnlineRollCallBase.del_flag == '0', OnlineRollCallBase.create_time > d1)
  630. if begin_date is not None and begin_date != '':
  631. begin_date = datetime.strptime(begin_date, "%Y-%m-%d")
  632. where = and_(where, OnlineRollCallBase.create_time > begin_date)
  633. if end_date is not None and end_date != '':
  634. end_date = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
  635. where = and_(where, OnlineRollCallBase.create_time < end_date)
  636. print(where)
  637. # 计算总条目数
  638. q = db.query(func.count(OnlineRollCallBase.id))
  639. q = q.filter(where)
  640. total = q.scalar()
  641. # 执行分页查询
  642. q = db.query(OnlineRollCallBase)
  643. q = q.filter(where)
  644. rows = q.order_by(OnlineRollCallBase.id.desc()).offset((page - 1) * page_size).limit(page_size).all()
  645. data = []
  646. for row in rows:
  647. duration_time = ""
  648. # 已结束
  649. if row.call_status == 2:
  650. if row.end_time is None:
  651. row.end_time = datetime.now()
  652. db.commit()
  653. time_diff = row.end_time - row.create_time
  654. # hours,minutes,seconds = str(time_diff).split(':')
  655. duration_time = str(time_diff)
  656. data.append({
  657. "id": row.id,
  658. "begin_time": get_datetime_str(row.create_time),
  659. "end_time": get_datetime_str(row.end_time),
  660. "duration_time": duration_time,
  661. "call_status": row.call_status,
  662. "ack_count": row.ack_count,
  663. "unack_count": row.unack_count
  664. })
  665. # 返回结果
  666. return {
  667. "code": 200,
  668. "msg": "查询成功",
  669. "data": data,
  670. "total": total
  671. }
  672. except Exception as e:
  673. # 处理异常
  674. traceback.print_exc()
  675. raise HTTPException(status_code=500, detail=str(e))
  676. #应答列表(我的)
  677. @router.get('/ack_list')
  678. async def get_event_list(
  679. request: Request,
  680. begin_date: str = Query('', description='开始时间'),
  681. end_date: str = Query('', description='结束时间'),
  682. page: int = Query(1, gt=0, description='页码'),
  683. page_size: int = Query(10, gt=0, description='pageSize'),
  684. db: Session = Depends(get_db),
  685. user_id = Depends(valid_access_token)
  686. ):
  687. try:
  688. is_myid_where = or_(OnlineRollCallDetail.standby_staff_id == user_id,
  689. OnlineRollCallDetail.leader_id == user_id,
  690. OnlineRollCallDetail.primary_staff_id == user_id,
  691. OnlineRollCallDetail.secondary_staff_id == user_id)
  692. where = and_(is_myid_where, OnlineRollCallDetail.del_flag == '0')
  693. if begin_date is not None and begin_date != '':
  694. begin_date = datetime.strptime(begin_date, "%Y-%m-%d")
  695. where = and_(where, OnlineRollCallDetail.create_time > begin_date)
  696. if end_date is not None and end_date != '':
  697. end_date = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
  698. where = and_(where, OnlineRollCallDetail.create_time < end_date)
  699. print(where)
  700. # 计算总条目数
  701. q = db.query(func.count(OnlineRollCallDetail.id))
  702. q = q.filter(where)
  703. total = q.scalar()
  704. # 执行分页查询
  705. q = db.query(OnlineRollCallDetail)
  706. q = q.filter(where)
  707. rows = q.order_by(OnlineRollCallDetail.id.desc()).offset((page - 1) * page_size).limit(page_size).all()
  708. data = []
  709. for row in rows:
  710. duration_time = ""
  711. img_url = ""
  712. # 已应答
  713. if row.ack_status == 1:
  714. file_info = db.query(OnlineRollCallFile).filter(and_(OnlineRollCallFile.foreign_key == str(row.id), OnlineRollCallFile.from_scenario == 'online_call_photo_file', OnlineRollCallFile.del_flag == '0')).first()
  715. if file_info is not None:
  716. img_url = file_info.storage_file_name
  717. time_diff = row.ack_time - row.create_time
  718. if time_diff.days < 0:
  719. duration_time = "超过{}天".format(abs(time_diff.days))
  720. else:
  721. hours,minutes,seconds = str(time_diff).split(':')
  722. duration_time = str(time_diff)
  723. data.append({
  724. "id": row.id,
  725. "create_time": get_datetime_str(row.create_time),
  726. "duration_time": duration_time,
  727. "ack_status": row.ack_status,
  728. "img_url": img_url
  729. })
  730. # 返回结果
  731. return {
  732. "code": 200,
  733. "msg": "查询成功",
  734. "data": data,
  735. "total": total
  736. }
  737. except Exception as e:
  738. # 处理异常
  739. traceback.print_exc()
  740. raise HTTPException(status_code=500, detail=str(e))
  741. # 点名统计(我的)
  742. @router.get("/summary")
  743. async def get_call_summary(request: Request,
  744. db: Session = Depends(get_db),
  745. user_id = Depends(valid_access_token)):
  746. is_myid_where = or_(OnlineRollCallDetail.standby_staff_id == user_id,
  747. OnlineRollCallDetail.leader_id == user_id,
  748. OnlineRollCallDetail.primary_staff_id == user_id,
  749. OnlineRollCallDetail.secondary_staff_id == user_id)
  750. try:
  751. call_count = db.query(OnlineRollCallDetail).filter(and_(is_myid_where, OnlineRollCallDetail.del_flag == '0')).count()
  752. ack_count = db.query(OnlineRollCallDetail).filter(and_(is_myid_where, OnlineRollCallDetail.del_flag == '0', OnlineRollCallDetail.ack_status == 1)).count()
  753. unack_count = db.query(OnlineRollCallDetail).filter(and_(is_myid_where, OnlineRollCallDetail.del_flag == '0', OnlineRollCallDetail.ack_status == 0)).count()
  754. data = {
  755. "call_count": call_count,
  756. "ack_count": ack_count,
  757. "unack_count": unack_count
  758. }
  759. return {
  760. "code": 200,
  761. "msg": "查询成功",
  762. "data": data
  763. }
  764. except Exception as e:
  765. # 处理异常
  766. traceback.print_exc()
  767. raise HTTPException(status_code=500, detail=str(e))
  768. @router.get("/export", response_class=FileResponse)
  769. async def get_export_xslx(
  770. request: Request,
  771. call_id: str,
  772. db: Session = Depends(get_db)):
  773. # 导出excel表
  774. wb = openpyxl.Workbook()
  775. ws = wb.active
  776. ws.cell(1, 1).value = "部门名称"
  777. ws.cell(1, 2).value = "值班领导"
  778. ws.cell(1, 3).value = "值班员"
  779. ws.cell(1, 4).value = "点名开始时间"
  780. ws.cell(1, 5).value = "应答状态"
  781. ws.cell(1, 6).value = "应答时间"
  782. q = db.query(OnlineRollCallDetail)
  783. q = q.filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.del_flag == '0')).order_by(OnlineRollCallDetail.ack_status.desc(), OnlineRollCallDetail.ack_time.asc())
  784. rows = q.all()
  785. excel_row = 2
  786. for row in rows:
  787. ws.cell(excel_row, 1).value = row.dept_name
  788. ws.cell(excel_row, 2).value = row.onduty_leader
  789. ws.cell(excel_row, 3).value = row.onduty_user
  790. ws.cell(excel_row, 4).value = get_datetime_str(row.create_time)
  791. ws.cell(excel_row, 5).value = get_ack_status_text(row.ack_status)
  792. ws.cell(excel_row, 6).value = get_datetime_str(row.ack_time)
  793. excel_row = excel_row + 1
  794. upload_path = '/data/download/mergefile'
  795. if os.path.exists(upload_path) == False:
  796. os.makedirs(upload_path)
  797. excel_file_name = new_guid() +".xlsx"
  798. save_path = os.path.join(upload_path, excel_file_name)
  799. wb.save(save_path)
  800. wb.close()
  801. return FileResponse(save_path)