call.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. from fastapi import APIRouter, Request, Depends, Query, HTTPException
  4. from database import get_db
  5. from sqlalchemy import text, exists, and_, or_, not_
  6. from sqlalchemy.orm import Session
  7. from sqlalchemy.sql import func
  8. from models import *
  9. import uuid
  10. import os
  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_dept
  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 exceptions import AppException
  25. from typing import List, Dict,Set
  26. router = APIRouter()
  27. @router.get("/dept_by_key", response_model=Dict)
  28. def dept_by_key(db: Session = Depends(get_db), area_name: str = Query(None), keyword: str = Query(None)):
  29. current_date = datetime.now().date()
  30. current_time = datetime.now().time()
  31. def get_dept_tree(db: Session, dept_id: int):
  32. dept = db.query(SysDept).filter(SysDept.dept_id == dept_id).first()
  33. if not dept:
  34. return None
  35. children = []
  36. for child in db.query(SysDept).filter(SysDept.parent_id == dept.dept_id).all():
  37. child = get_dept_tree(db, child.dept_id)
  38. if child is not None:
  39. children.append(child)
  40. # 获取值班信息
  41. '''
  42. q = db.query(DutyShift)
  43. q = q.filter(DutyShift.shift_date == current_date)
  44. q = q.filter(DutyShift.shfit_status == 0)
  45. q = q.filter(DutyShift.start_time < current_time).filter(DutyShift.end_time > current_time)
  46. shift_row = q.first()
  47. if shift_row is not None:
  48. children.append({
  49. "uuid":str(uuid.uuid4()).replace('-',''),
  50. "id": shift_row.shift_id,
  51. "label": str(shift_row.shift_id),
  52. "deptType": False
  53. })
  54. '''
  55. dept_info = {
  56. "uuid":str(uuid.uuid4()).replace('-',''),
  57. "id": dept.dept_id,
  58. "label": dept.dept_name,
  59. "deptType": True
  60. }
  61. if len(children) > 0:
  62. dept_info["children"] = children
  63. return dept_info
  64. dept_id = db_dept.get_dept_id_by_name(db, area_name)
  65. if dept_id == 0:
  66. return {
  67. "code": 200,
  68. "msg": "成功",
  69. "data": []
  70. }
  71. print('dept_id:', dept_id)
  72. data = get_dept_tree(db, dept_id)
  73. return {
  74. "code": 200,
  75. "msg": "成功",
  76. "data": [data]
  77. }
  78. # 一键点名全市至区县
  79. @router.post("/create_by_city_to_area")
  80. async def create_by_city_to_area(
  81. db: Session = Depends(get_db),
  82. user_id = Depends(valid_access_token)
  83. ):
  84. current_date = datetime.now().date()
  85. current_time = datetime.now().time()
  86. try:
  87. # 过滤当前时间内的值班人员
  88. q = db.query(DutyShift).filter(func.char_length(DutyShift.area_code) <= 6)
  89. q = q.filter(DutyShift.shift_date == current_date)
  90. q = q.filter(DutyShift.shfit_status == 0)
  91. q = q.filter(DutyShift.start_time < current_time).filter(DutyShift.end_time > current_time)
  92. rows = q.all()
  93. user_count = len(rows)
  94. if user_count == 0:
  95. raise AppException(500, "暂无相关值班人员信息")
  96. new_call = OnlineRollCallBase(
  97. call_type = 1,
  98. recorded_by = user_id,
  99. create_time = datetime.now(),
  100. del_flag = '0',
  101. call_status = 1,
  102. user_count = user_count,
  103. ack_count = 0,
  104. unack_count = user_count,
  105. remark = '',
  106. update_time = datetime.now()
  107. )
  108. db.add(new_call)
  109. db.commit()
  110. db.refresh(new_call)
  111. new_call_id = new_call.id
  112. dept_list = []
  113. for row in rows:
  114. shift_id = row.shift_id
  115. shift_dept_id = row.dept_id
  116. shift_dept_name = db_dept.get_dept_name_by_id(db, row.dept_id)
  117. onduty_user = db_user.get_nick_name_by_id(db, row.primary_staff_id)
  118. onduty_leader = db_user.get_nick_name_by_id(db, row.leader_id)
  119. video_url = "#"
  120. call_url = "#"
  121. # 避免同一个部门重复
  122. if shift_dept_id in dept_list:
  123. continue
  124. dept_list.append(shift_dept_id)
  125. new_detail = OnlineRollCallDetail(
  126. pid = new_call_id,
  127. shift_id = shift_id,
  128. dept_id = shift_dept_id,
  129. dept_name = shift_dept_name,
  130. onduty_user = onduty_user,
  131. onduty_leader = onduty_leader,
  132. video_url = video_url,
  133. call_url = call_url,
  134. ack_status = 0,
  135. act_time = None,
  136. create_time = datetime.now(),
  137. del_flag = '0',
  138. ack_type = 0
  139. )
  140. db.add(new_detail)
  141. db.commit()
  142. return {
  143. "code": 200,
  144. "msg": "点名创建成功",
  145. "data": new_call_id
  146. }
  147. except AppException as e:
  148. return {
  149. "code": e.code,
  150. "msg": e.msg
  151. }
  152. except Exception as e:
  153. traceback.print_exc()
  154. # 处理异常
  155. raise HTTPException(status_code=500, detail=str(e))
  156. # 一键点名全市至镇街
  157. @router.post("/create_by_city_to_district")
  158. async def create_by_city_to_district(
  159. db: Session = Depends(get_db),
  160. user_id = Depends(valid_access_token)
  161. ):
  162. current_date = datetime.now().date()
  163. current_time = datetime.now().time()
  164. try:
  165. # 过滤当前时间内的值班人员
  166. q = db.query(DutyShift).filter(func.char_length(DutyShift.area_code) <= 9)
  167. q = q.filter(DutyShift.shift_date == current_date)
  168. q = q.filter(DutyShift.shfit_status == 0)
  169. q = q.filter(DutyShift.start_time < current_time).filter(DutyShift.end_time > current_time)
  170. rows = q.all()
  171. user_count = len(rows)
  172. if user_count == 0:
  173. raise AppException(500, "暂无相关值班人员信息")
  174. new_call = OnlineRollCallBase(
  175. call_type = 1,
  176. recorded_by = user_id,
  177. create_time = datetime.now(),
  178. del_flag = '0',
  179. call_status = 1,
  180. user_count = user_count,
  181. ack_count = 0,
  182. unack_count = user_count,
  183. remark = '',
  184. update_time = datetime.now()
  185. )
  186. db.add(new_call)
  187. db.commit()
  188. db.refresh(new_call)
  189. new_call_id = new_call.id
  190. dept_list = []
  191. for row in rows:
  192. shift_id = row.shift_id
  193. shift_dept_id = row.dept_id
  194. shift_dept_name = db_dept.get_dept_name_by_id(db, row.dept_id)
  195. onduty_user = db_user.get_nick_name_by_id(db, row.primary_staff_id)
  196. onduty_leader = db_user.get_nick_name_by_id(db, row.leader_id)
  197. video_url = "#"
  198. call_url = "#"
  199. # 避免同一个部门重复
  200. if shift_dept_id in dept_list:
  201. continue
  202. dept_list.append(shift_dept_id)
  203. new_detail = OnlineRollCallDetail(
  204. pid = new_call_id,
  205. shift_id = shift_id,
  206. dept_id = shift_dept_id,
  207. dept_name = shift_dept_name,
  208. onduty_user = onduty_user,
  209. onduty_leader = onduty_leader,
  210. video_url = video_url,
  211. call_url = call_url,
  212. ack_status = 0,
  213. act_time = None,
  214. create_time = datetime.now(),
  215. del_flag = '0',
  216. ack_type = 0
  217. )
  218. db.add(new_detail)
  219. db.commit()
  220. return {
  221. "code": 200,
  222. "msg": "点名创建成功",
  223. "data": new_call_id
  224. }
  225. except AppException as e:
  226. return {
  227. "code": e.code,
  228. "msg": e.msg
  229. }
  230. except Exception as e:
  231. traceback.print_exc()
  232. # 处理异常
  233. raise HTTPException(status_code=500, detail=str(e))
  234. # 新建点名(分区/县点名)
  235. @router.post("/create_by_dept_ids")
  236. async def create_by_dept_ids(
  237. db: Session = Depends(get_db),
  238. body = Depends(remove_xss_json),
  239. user_id = Depends(valid_access_token)
  240. ):
  241. current_date = datetime.now().date()
  242. current_time = datetime.now().time()
  243. try:
  244. if len(body['depts']) == 0:
  245. raise AppException(500, "请勾选部门")
  246. new_call = OnlineRollCallBase(
  247. call_type = 3,
  248. recorded_by = user_id,
  249. create_time = datetime.now(),
  250. del_flag = '0',
  251. call_status = 1,
  252. user_count = 0,
  253. ack_count = 0,
  254. unack_count = 0,
  255. remark = body['remark'],
  256. update_time = datetime.now()
  257. )
  258. db.add(new_call)
  259. db.commit()
  260. db.refresh(new_call)
  261. new_call_id = new_call.id
  262. for dept_id in body['depts']:
  263. # 过滤当前时间内的值班人员
  264. q = db.query(DutyShift).filter(DutyShift.dept_id == dept_id)
  265. q = q.filter(DutyShift.shift_date == current_date)
  266. q = q.filter(DutyShift.shfit_status == 0)
  267. q = q.filter(DutyShift.start_time < current_time).filter(DutyShift.end_time > current_time)
  268. row = q.first()
  269. if row is not None:
  270. print(dept_id)
  271. shift_id = row.shift_id
  272. shift_dept_id = row.dept_id
  273. shift_dept_name = db_dept.get_dept_name_by_id(db, row.dept_id)
  274. onduty_user = db_user.get_nick_name_by_id(db, row.primary_staff_id)
  275. onduty_leader = db_user.get_nick_name_by_id(db, row.leader_id)
  276. video_url = "#"
  277. call_url = "#"
  278. new_detail = OnlineRollCallDetail(
  279. pid = new_call_id,
  280. shift_id = shift_id,
  281. dept_id = shift_dept_id,
  282. dept_name = shift_dept_name,
  283. onduty_user = onduty_user,
  284. onduty_leader = onduty_leader,
  285. video_url = video_url,
  286. call_url = call_url,
  287. ack_status = 0,
  288. act_time = None,
  289. create_time = datetime.now(),
  290. del_flag = '0',
  291. ack_type = 0
  292. )
  293. db.add(new_detail)
  294. db.commit()
  295. # 检查多次,避免人员为空
  296. user_count = db.query(OnlineRollCallDetail).filter(OnlineRollCallDetail.pid == new_call_id).count()
  297. if user_count == 0:
  298. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == new_call_id).delete()
  299. db.commit()
  300. raise AppException(500, "暂无相关值班人员信息")
  301. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == new_call_id).update({"user_count": user_count, "unack_count": user_count})
  302. db.commit()
  303. return {
  304. "code": 200,
  305. "msg": "点名创建成功",
  306. "data": new_call_id
  307. }
  308. except AppException as e:
  309. return {
  310. "code": e.code,
  311. "msg": e.msg
  312. }
  313. except Exception as e:
  314. traceback.print_exc()
  315. # 处理异常
  316. raise HTTPException(status_code=500, detail=str(e))
  317. # 结束应答
  318. @router.post("/end")
  319. async def end_call(
  320. db: Session = Depends(get_db),
  321. body = Depends(remove_xss_json),
  322. user_id = Depends(valid_access_token)
  323. ):
  324. call_id = body['call_id']
  325. row = db.query(OnlineRollCallBase).filter(and_(OnlineRollCallBase.id == call_id, OnlineRollCallBase.del_flag == '0')).first()
  326. if row is None:
  327. return {
  328. "code": 500,
  329. "msg": "点名记录不存在"
  330. }
  331. if row.call_status != 1:
  332. return {
  333. "code": 500,
  334. "msg": "点名记录状态已结束"
  335. }
  336. row.end_time = datetime.now()
  337. row.call_status = 2 # 结束
  338. row.update_time = datetime.now()
  339. db.commit()
  340. return {
  341. "code": 200,
  342. "msg": "点名结束成功"
  343. }
  344. # 标记用户已应答
  345. @router.post("/ack")
  346. async def ack_all(
  347. db: Session = Depends(get_db),
  348. body = Depends(remove_xss_json),
  349. user_id = Depends(valid_access_token)
  350. ):
  351. call_id = body['call_id']
  352. ack_type = body['ack_type']
  353. base_row = db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).first()
  354. if base_row is None:
  355. return {
  356. "code": 500,
  357. "msg": "点名记录不存在"
  358. }
  359. detail_row = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.user_id == user_id)).first()
  360. if detail_row is None:
  361. return {
  362. "code": 500,
  363. "msg": "点名记录不存在!"
  364. }
  365. detail_row.ack_type = ack_type
  366. detail_row.act_time = datetime.now()
  367. db.commit()
  368. # 统计应答数
  369. ack_count = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.ack_status == 1)).count()
  370. # 统计未应答数
  371. unack_count = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.pid == call_id, OnlineRollCallDetail.ack_status == 2)).count()
  372. db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).update({
  373. "ack_count": ack_count, "unack_count": unack_count, "update_time": datetime.now()
  374. })
  375. db.commit()
  376. return {
  377. "code": 200,
  378. "msg": "应答成功"
  379. }
  380. # 查询是否有我的待应答记录(提醒)
  381. @router.post("/mycall")
  382. async def query_mycall(
  383. db: Session = Depends(get_db),
  384. user_id = Depends(valid_access_token)
  385. ):
  386. rows = db.query(OnlineRollCallDetail).filter(and_(OnlineRollCallDetail.user_id == user_id, OnlineRollCallDetail.ack_status == 0)).all()
  387. data = []
  388. for row in rows:
  389. call_id = row.pid
  390. base_row = db.query(OnlineRollCallBase).filter(and_(OnlineRollCallBase.id == call_id, OnlineRollCallBase.del_flag == '0')).first()
  391. data.append({
  392. "call_id": call_id,
  393. "create_time": get_datetime_str(base_row.create_time)
  394. })
  395. return {
  396. "code": 200,
  397. "msg": "查询成功",
  398. "data": data,
  399. "total": len(data)
  400. }
  401. #应答详情
  402. @router.get('/detail')
  403. async def get_event_detail(
  404. request: Request,
  405. call_id: str = Query(None, description='点名ID'),
  406. db: Session = Depends(get_db)):
  407. try:
  408. base_row = db.query(OnlineRollCallBase).filter(OnlineRollCallBase.id == call_id).first()
  409. if base_row is None:
  410. return {
  411. "code": 500,
  412. "msg": "点名记录不存在"
  413. }
  414. data = get_model_dict(base_row)
  415. data['begin_time'] = get_datetime_str(data['create_time'])
  416. data['update_time'] = get_datetime_str(data['update_time'])
  417. data['duration_time'] = ''
  418. # 已结束
  419. if data['call_status'] == 2:
  420. time_diff = base_row.end_time - base_row.create_time
  421. # hours,minutes,seconds = str(time_diff).split(':')
  422. data['duration_time'] = str(time_diff)
  423. detail_rows = db.query(OnlineRollCallDetail).filter(OnlineRollCallDetail.pid == call_id).all()
  424. items = []
  425. for row in detail_rows:
  426. detail_info = get_model_dict(row)
  427. detail_info['begin_time'] = get_datetime_str(detail_info['create_time'])
  428. detail_info['act_time'] = get_datetime_str(detail_info['act_time'])
  429. detail_info['ack_status_text'] = get_ack_status_text(detail_info['ack_status'])
  430. items.append(detail_info)
  431. data['items'] = items
  432. return {
  433. "code": 200,
  434. "msg": "查询成功",
  435. "data": data
  436. }
  437. except Exception as e:
  438. # 处理异常
  439. traceback.print_exc()
  440. raise HTTPException(status_code=500, detail=str(e))
  441. def get_ack_status_text(act_status: int) -> str:
  442. if act_status == 0:
  443. return '未应答'
  444. elif act_status == 1:
  445. return '已接通'
  446. elif act_status == 2:
  447. return '呼叫中'
  448. else:
  449. return str(act_status)
  450. #应答详情
  451. @router.get('/list')
  452. async def get_event_list(
  453. request: Request,
  454. begin_date: str = Query('', description='开始时间'),
  455. end_date: str = Query('', description='结束时间'),
  456. page: int = Query(1, gt=0, description='页码'),
  457. page_size: int = Query(10, gt=0, description='pageSize'),
  458. db: Session = Depends(get_db)):
  459. try:
  460. where = and_(OnlineRollCallBase.del_flag == '0')
  461. if begin_date is not None and begin_date != '':
  462. begin_date = datetime.strptime(begin_date, "%Y-%m-%d")
  463. where = and_(where, OnlineRollCallBase.create_time > begin_date)
  464. if end_date is not None and end_date != '':
  465. end_date = datetime.strptime(end_date, "%Y-%m-%d") + timedelta(days=1)
  466. where = and_(where, OnlineRollCallBase.create_time < end_date)
  467. print(where)
  468. # 计算总条目数
  469. q = db.query(func.count(OnlineRollCallBase.id))
  470. q = q.filter(where)
  471. total = q.scalar()
  472. # 执行分页查询
  473. q = db.query(OnlineRollCallBase)
  474. q = q.filter(where)
  475. rows = q.order_by(OnlineRollCallBase.id.desc()).offset((page - 1) * page_size).limit(page_size).all()
  476. data = []
  477. for row in rows:
  478. duration_time = ""
  479. # 已结束
  480. if row.call_status == 2:
  481. time_diff = row.end_time - row.create_time
  482. # hours,minutes,seconds = str(time_diff).split(':')
  483. duration_time = str(time_diff)
  484. data.append({
  485. "id": row.id,
  486. "begin_time": get_datetime_str(row.create_time),
  487. "end_time": get_datetime_str(row.end_time),
  488. "duration_time": duration_time,
  489. "call_status": row.call_status,
  490. "ack_count": row.ack_count,
  491. "unack_count": row.unack_count
  492. })
  493. # 返回结果
  494. return {
  495. "code": 200,
  496. "msg": "查询成功",
  497. "data": data,
  498. "total": total
  499. }
  500. except Exception as e:
  501. # 处理异常
  502. traceback.print_exc()
  503. raise HTTPException(status_code=500, detail=str(e))