call.py 33 KB

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