duty.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. from fastapi import APIRouter, Request, Depends, HTTPException, Query, BackgroundTasks
  2. from sqlalchemy.exc import IntegrityError
  3. from fastapi.responses import HTMLResponse, FileResponse
  4. from fastapi.responses import JSONResponse
  5. from database import get_db
  6. from sqlalchemy import text, exists, and_, or_, not_
  7. from sqlalchemy.orm import Session
  8. from models import *
  9. import json
  10. import random
  11. from sqlalchemy import create_engine, select
  12. from typing import Optional
  13. from utils.StripTagsHTMLParser import *
  14. from common.db import db_event_management, db_user, db_area, db_emergency_plan
  15. from common.security import valid_access_token
  16. import traceback
  17. from utils import *
  18. from datetime import datetime, timedelta
  19. from common import YzyApi
  20. from common.db import db_dict
  21. from urllib.parse import quote
  22. import base64
  23. from config import settings
  24. from extensions import logger
  25. import os
  26. from exceptions import *
  27. import openpyxl
  28. router = APIRouter()
  29. @router.get("/duty_by_day")
  30. async def duty_by_day(
  31. day: str,
  32. db: Session = Depends(get_db),
  33. user_id = Depends(valid_access_token)
  34. ):
  35. try:
  36. data = {}
  37. shift_status = 0
  38. handover_time = None
  39. current_time = datetime.now().time()
  40. date = datetime.strptime(day, "%Y-%m-%d")
  41. # 人员
  42. user_row = db_user.get_user_info(db, user_id)
  43. dept_id = user_row.dept_id
  44. # 默认值
  45. data['users'] = {
  46. "user1": "-",
  47. "user2": "-",
  48. "user3": "-",
  49. "user4": "-"
  50. }
  51. # 当前用户的同一个部门的值班
  52. where = and_(DutySchedule.duty_date == date,DutySchedule.del_flag!='2')
  53. # where = and_(where, DutyShift.dept_id == dept_id)
  54. subquery = db.query(
  55. DutySchedule.duty_date,
  56. DutySchedule.shift_type,
  57. func.max(DutySchedule.update_time).label("latest_create_time")
  58. ).filter(DutySchedule.del_flag != '2').group_by(
  59. DutySchedule.duty_date,
  60. DutySchedule.shift_type
  61. ).subquery()
  62. row = db.query(DutySchedule).filter(where)
  63. row = row.join(
  64. subquery,
  65. and_(
  66. DutySchedule.duty_date == subquery.c.duty_date,
  67. DutySchedule.shift_type == subquery.c.shift_type,
  68. DutySchedule.update_time == subquery.c.latest_create_time
  69. )
  70. ).all()
  71. shift_id = [info.id for info in row]
  72. if len(shift_id)>0:
  73. from .schedule import duty_id_get_user_id,user_id_get_info
  74. user_info = {"user1": [],
  75. "user2": "-",
  76. "user3": [],
  77. "user4": "-"}
  78. for d in shift_id:
  79. user_data = []
  80. user_list = duty_id_get_user_id(db, d)
  81. for user_info1 in user_list:
  82. contact_info = user_id_get_info(db, user_info1.personnel_id)
  83. if user_info1.position_id ==1:
  84. user_info['user1'].append(contact_info.name)
  85. if user_info1.position_id ==8:
  86. user_info['user3'].append(contact_info.name)
  87. # user_info = get_model_dict(row)
  88. user_info['user1'] = '、'.join(user_info['user1'])
  89. user_info['user3'] = '、'.join(user_info['user3'])
  90. data['users'] = user_info
  91. # 提醒事项
  92. where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '1', DutyNotify.shift_id.in_(shift_id))
  93. rows = db.query(DutyNotify).filter(where).all()
  94. items = []
  95. for row in rows:
  96. items.append({
  97. "text": row.notify_content,
  98. "time": get_datetime_str(row.create_time)
  99. })
  100. data['remainds'] = items
  101. # 待办事项
  102. where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '2', DutyNotify.shift_id.in_(shift_id))
  103. rows = db.query(DutyNotify).filter(where).all()
  104. items = []
  105. for row in rows:
  106. items.append({
  107. "text": row.notify_content,
  108. "time": get_datetime_str(row.create_time)
  109. })
  110. data['todos'] = items
  111. data['shift_id'] = shift_id
  112. data['shift_status'] = shift_status
  113. data['handover_time'] = ''
  114. # 目前不知道有什么用
  115. data['days'] = []
  116. return {
  117. "code": 200,
  118. "msg": "查询成功",
  119. "data": data
  120. }
  121. except AppException as e:
  122. return {
  123. "code": e.code,
  124. "msg": e.msg
  125. }
  126. except Exception as e:
  127. traceback.print_exc()
  128. # 处理异常
  129. raise HTTPException(status_code=500, detail=str(e))
  130. @router.get("/my_calendar_by_month")
  131. async def calendar_by_month(
  132. date: str = Query(None, description="月份"),
  133. db: Session = Depends(get_db),
  134. user_id=Depends(valid_access_token)
  135. ):
  136. the_year = datetime.now().year
  137. the_month = datetime.now().month
  138. if date is not None and date != '':
  139. arr = date.split("-")
  140. the_year = arr[0]
  141. the_month = arr[1]
  142. try:
  143. from utils.ry_system_util import user_id_get_user_info
  144. from .schedule import mobile_phone_get_dept_id,get_duty_unit_id_list
  145. from common.enc import mpfun
  146. now_user_info = user_id_get_user_info(db, user_id)
  147. if now_user_info:
  148. user_where = (DutySchedule.duty_unit == mobile_phone_get_dept_id(db, mpfun.dec_data(now_user_info.phonenumber),
  149. get_duty_unit_id_list(db)))
  150. else:
  151. return {
  152. "code": 200,
  153. "msg": "查询成功",
  154. "data": []
  155. }
  156. # user_where = or_(DutyShift.leader_id == user_id, DutyShift.primary_staff_id == user_id,
  157. # DutyShift.secondary_staff_id == user_id, DutyShift.standby_staff_id == user_id)
  158. where = and_(func.extract('year', DutySchedule.duty_date) == the_year,
  159. func.extract('month', DutySchedule.duty_date) == the_month)
  160. where = and_(where, user_where,DutySchedule.del_flag != '2')
  161. rows = db.query(DutySchedule.duty_date).distinct().filter(where).all()
  162. data = []
  163. for row in rows:
  164. data.append({
  165. "date": row.duty_date,
  166. "color": "a2d7f1"
  167. })
  168. return {
  169. "code": 200,
  170. "msg": "查询成功",
  171. "data": data
  172. }
  173. except AppException as e:
  174. return {
  175. "code": e.code,
  176. "msg": e.msg
  177. }
  178. except Exception as e:
  179. traceback.print_exc()
  180. # 处理异常
  181. raise HTTPException(status_code=500, detail=str(e))
  182. # @router.get("/duty_by_day")
  183. # async def duty_by_day(
  184. # day: str,
  185. # db: Session = Depends(get_db),
  186. # user_id=Depends(valid_access_token)
  187. # ):
  188. # try:
  189. # data = {}
  190. # shift_id = 0
  191. # shift_status = 0
  192. # handover_time = None
  193. #
  194. # current_time = datetime.now().time()
  195. # date = datetime.strptime(day, "%Y-%m-%d")
  196. #
  197. # # 人员
  198. # user_row = db_user.get_user_info(db, user_id)
  199. # dept_id = user_row.dept_id
  200. #
  201. # # 默认值
  202. # data['users'] = {
  203. # "user1": "-",
  204. # "user2": "-",
  205. # "user3": "-",
  206. # "user4": "-"
  207. # }
  208. #
  209. # # 当前用户的同一个部门的值班
  210. # where = and_(DutyShift.shift_date == date, DutyShift.start_time < current_time)
  211. # # where = and_(where, DutyShift.dept_id == dept_id)
  212. # row = db.query(DutyShift).filter(where).first()
  213. # if row is not None:
  214. # shift_id = row.shift_id
  215. # shift_status = row.shift_status
  216. # handover_time = row.handover_time
  217. #
  218. # user_info = get_model_dict(row)
  219. # user_info['user1'] = db_user.get_nick_name_by_id(db, user_info['leader_id'])
  220. # user_info['user2'] = db_user.get_nick_name_by_id(db, user_info['primary_staff_id'])
  221. # user_info['user3'] = db_user.get_nick_name_by_id(db, user_info['secondary_staff_id'])
  222. # user_info['user4'] = db_user.get_nick_name_by_id(db, user_info['standby_staff_id'])
  223. #
  224. # data['users'] = user_info
  225. #
  226. # # 提醒事项
  227. # where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '1', DutyNotify.shift_id == shift_id)
  228. # rows = db.query(DutyNotify).filter(where).all()
  229. # items = []
  230. # for row in rows:
  231. # items.append({
  232. # "text": row.notify_content,
  233. # "time": get_datetime_str(row.create_time)
  234. # })
  235. # data['remainds'] = items
  236. #
  237. # # 待办事项
  238. # where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '2', DutyNotify.shift_id == shift_id)
  239. # rows = db.query(DutyNotify).filter(where).all()
  240. # items = []
  241. # for row in rows:
  242. # items.append({
  243. # "text": row.notify_content,
  244. # "time": get_datetime_str(row.create_time)
  245. # })
  246. # data['todos'] = items
  247. #
  248. # data['shift_id'] = shift_id
  249. # data['shift_status'] = shift_status
  250. # data['handover_time'] = get_datetime_str(handover_time)
  251. #
  252. # # 目前不知道有什么用
  253. # data['days'] = []
  254. #
  255. # return {
  256. # "code": 200,
  257. # "msg": "查询成功",
  258. # "data": data
  259. # }
  260. #
  261. # except AppException as e:
  262. # return {
  263. # "code": e.code,
  264. # "msg": e.msg
  265. # }
  266. #
  267. # except Exception as e:
  268. # traceback.print_exc()
  269. # # 处理异常
  270. # raise HTTPException(status_code=500, detail=str(e))
  271. # 暂时没用
  272. # @router.get("/my_calendar_by_month")
  273. # async def calendar_by_month(
  274. # date: str = Query(None, description="月份"),
  275. # db: Session = Depends(get_db),
  276. # user_id = Depends(valid_access_token)
  277. # ):
  278. # the_year = datetime.now().year
  279. # the_month = datetime.now().month
  280. # if date is not None and date != '':
  281. # arr = date.split("-")
  282. # the_year = arr[0]
  283. # the_month = arr[1]
  284. #
  285. # try:
  286. # user_where = or_(DutyShift.leader_id == user_id, DutyShift.primary_staff_id == user_id, DutyShift.secondary_staff_id == user_id, DutyShift.standby_staff_id == user_id)
  287. # where = and_(func.extract('year', DutyShift.shift_date) == the_year, func.extract('month', DutyShift.shift_date) == the_month)
  288. # where = and_(where, user_where)
  289. # rows = db.query(DutyShift.shift_date).distinct().filter(where).all()
  290. # data = []
  291. # for row in rows:
  292. # data.append({
  293. # "date": row.shift_date,
  294. # "color": "a2d7f1"
  295. # })
  296. # return {
  297. # "code": 200,
  298. # "msg": "查询成功",
  299. # "data": data
  300. # }
  301. #
  302. # except AppException as e:
  303. # return {
  304. # "code": e.code,
  305. # "msg": e.msg
  306. # }
  307. #
  308. # except Exception as e:
  309. # traceback.print_exc()
  310. # # 处理异常
  311. # raise HTTPException(status_code=500, detail=str(e))
  312. #
  313. # 新增提醒或者待办
  314. @router.post("/add_notify")
  315. async def create_by_city_to_area(
  316. db: Session = Depends(get_db),
  317. body = Depends(remove_xss_json),
  318. user_id = Depends(valid_access_token)
  319. ):
  320. try:
  321. shift_id = body['shift_id']
  322. notify_type = body['notify_type']
  323. notify_content = body['notify_content']
  324. new_notify = DutyNotify(
  325. shift_id = shift_id,
  326. notify_type = notify_type,
  327. notify_content = notify_content,
  328. create_time = datetime.now(),
  329. del_flag = '0',
  330. recorded_by = user_id
  331. )
  332. db.add(new_notify)
  333. db.commit()
  334. db.refresh(new_notify)
  335. new_notify_id = new_notify.id
  336. return {
  337. "code": 200,
  338. "msg": "事项创建成功",
  339. "data": new_notify_id
  340. }
  341. except AppException as e:
  342. return {
  343. "code": e.code,
  344. "msg": e.msg
  345. }
  346. except Exception as e:
  347. traceback.print_exc()
  348. # 处理异常
  349. raise HTTPException(status_code=500, detail=str(e))
  350. # 交班
  351. @router.post("/handover")
  352. async def handover(
  353. db: Session = Depends(get_db),
  354. body = Depends(remove_xss_json),
  355. user_id = Depends(valid_access_token)
  356. ):
  357. try:
  358. shift_id = body['shift_id']
  359. where = and_(DutyShift.shift_id == shift_id)
  360. row = db.query(DutyShift).filter(where).first()
  361. if row is None:
  362. raise AppException("班次不存在")
  363. if row.shift_status == 1:
  364. raise AppException("班次已交班,不用重复操作")
  365. row.shift_status = 1
  366. row.handover_time = datetime.now()
  367. row.handover_user_id = user_id
  368. db.commit()
  369. return {
  370. "code": 200,
  371. "msg": "交班成功",
  372. "data": shift_id
  373. }
  374. except AppException as e:
  375. return {
  376. "code": e.code,
  377. "msg": e.msg
  378. }
  379. except Exception as e:
  380. traceback.print_exc()
  381. # 处理异常
  382. raise HTTPException(status_code=500, detail=str(e))
  383. # 值班表查询
  384. @router.get("/duty_book_by_area")
  385. async def duty_book_by_year_and(
  386. year: str,
  387. area: str,
  388. db: Session = Depends(get_db)
  389. ):
  390. try:
  391. data = []
  392. where = and_(DutyBook.del_flag == '0', DutyBook.year == year, DutyBook.area_code == area)
  393. rows = db.query(DutyBook).filter(where).order_by(DutyBook.month.asc()).all()
  394. for row in rows:
  395. file_url = ""
  396. file_row = db.query(DutyFile).filter(and_(DutyFile.del_flag == '0', DutyFile.from_scenario == 'duty_book', DutyFile.foreign_key == row.id)).first()
  397. if file_row is not None:
  398. file_url = file_row.storage_file_name
  399. data.append({
  400. "id": row.id,
  401. "name": get_month_text(row.month)+"月份",
  402. "name2": get_month_text(row.month)+"月份排班表.xlsx",
  403. "time": row.create_time.strftime("%m-%d %H:%M"),
  404. "url": file_url
  405. })
  406. return {
  407. "code": 200,
  408. "msg": "交班成功",
  409. "data": data
  410. }
  411. except AppException as e:
  412. return {
  413. "code": e.code,
  414. "msg": e.msg
  415. }
  416. except Exception as e:
  417. traceback.print_exc()
  418. # 处理异常
  419. raise HTTPException(status_code=500, detail=str(e))
  420. # 上传排班表
  421. @router.post("/upload_duty_book")
  422. async def upload_duty_book(
  423. db: Session = Depends(get_db),
  424. body = Depends(remove_xss_json),
  425. user_id = Depends(valid_access_token)
  426. ):
  427. try:
  428. dept_id = 0
  429. user_row = db.query(SysUser).filter(SysUser.user_id == user_id).first()
  430. dept_id = user_row.dept_id
  431. area = body['area']
  432. year = body['year']
  433. month = body['month']
  434. # 先导入附件
  435. # 附件
  436. if 'files' not in body:
  437. raise AppException(500, "请上传值班表")
  438. # 从1号开始
  439. date = datetime.strptime(year + "-" + month + "-01", "%Y-%m-%d")
  440. users = []
  441. fileName = body['files'][0]
  442. users = import_duty_book_from_file(int(year), int(month), date, fileName)
  443. if len(users) == 0:
  444. raise AppException(500, "无法获取值班人员")
  445. # 标记之前的导入已删除
  446. old_book_id = 0
  447. where = and_(DutyBook.del_flag == '0', DutyBook.year == year, DutyBook.area_code == area)
  448. row = db.query(DutyBook).filter(where).order_by(DutyBook.month.asc()).first()
  449. if row is not None:
  450. old_book_id = row.id
  451. row.del_flag = '2'
  452. db.commit()
  453. # 新建导入
  454. new_book = DutyBook(
  455. year = year, month = month, area_code = area,
  456. recorded_by = user_id, create_time = datetime.now(), del_flag = '0'
  457. )
  458. db.add(new_book)
  459. db.commit()
  460. db.refresh(new_book)
  461. new_book_id = new_book.id
  462. for (date, item) in users.items():
  463. onduty_leader = item['onduty_leader']
  464. onduty_user = item['onduty_user']
  465. new_shift = DutyShift(
  466. shift_date = date,
  467. # 目前只是值班一整天
  468. start_time = "00:00",
  469. end_time = "23:59",
  470. leader_id = 0,
  471. primary_staff_id = 0,
  472. onduty_leader = onduty_leader,
  473. onduty_user = onduty_user,
  474. # Excel没用到这两个字段
  475. secondary_staff_id = -1,
  476. standby_staff_id = -1,
  477. duty_type = "综合值班",
  478. shift_status = 0,
  479. handover_user_id = 0,
  480. handover_time = None,
  481. dept_id = -1, # 这个字段没用
  482. area_code = area,
  483. del_flag = '0',
  484. book_id = new_book_id
  485. )
  486. db.add(new_shift)
  487. db.commit()
  488. # 标记之前的值班信息已删除
  489. where = and_(DutyShift.del_flag == '0', DutyShift.book_id == old_book_id)
  490. db.query(DutyShift).filter(where).update({"del_flag": '2'})
  491. db.commit()
  492. new_file = DutyFile(
  493. file_name=fileName["name"],
  494. storage_file_name=fileName["url"],
  495. file_path=f'/data/upload/mergefile/uploads/{fileName["url"]}',
  496. file_size=os.path.getsize(f'/data/upload/mergefile/uploads/{fileName["url"]}'),
  497. foreign_key=str(new_book_id),
  498. from_scenario="duty_book",
  499. update_time=datetime.now(),
  500. create_time=datetime.now(),
  501. create_by=user_id,
  502. create_dept=dept_id,
  503. del_flag='0',
  504. status=0,
  505. )
  506. db.add(new_file)
  507. db.commit()
  508. db.refresh(new_file)
  509. return {
  510. "code": 200,
  511. "msg": "上传成功",
  512. "data": new_file.id
  513. }
  514. except AppException as e:
  515. return {
  516. "code": e.code,
  517. "msg": e.msg
  518. }
  519. except Exception as e:
  520. traceback.print_exc()
  521. # 处理异常
  522. raise HTTPException(status_code=500, detail=str(e))
  523. def import_duty_book_from_file(year: int, month: int, date: datetime, fileName: dict) -> dict:
  524. file_path = f'/data/upload/mergefile/uploads/{fileName["url"]}'
  525. wb = openpyxl.load_workbook(file_path)
  526. ws = wb.active
  527. rows = []
  528. for row in ws.iter_rows(values_only=True):
  529. rows.append(list(row))
  530. print(list(row))
  531. users = {}
  532. while date.month == month:
  533. day = datetime.strftime(date, "%m月%d日")
  534. for x in range(len(rows)):
  535. row = rows[x]
  536. for y in range(len(row)):
  537. cell = row[y]
  538. if cell == day:
  539. try:
  540. # 带班领导
  541. onduty_leader = rows[x+1][y]
  542. # 值班人员
  543. onduty_user = rows[x+2][y]
  544. if onduty_leader is None:
  545. raise AppException(500, "无法获取"+day+"的带班领导")
  546. if onduty_user is None:
  547. raise AppException(500, "无法获取"+day+"的值班人员")
  548. # date1 = date.strftime("%Y-%m-%d")
  549. users[date] = {"day": day, "onduty_leader": onduty_leader, "onduty_user": onduty_user}
  550. except Exception as e:
  551. raise AppException(500, "无法获取"+day+"的值班人员")
  552. break
  553. date = date + timedelta(days=1)
  554. return users