call.py 28 KB

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