duty.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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_id = 0
  38. shift_status = 0
  39. handover_time = None
  40. current_time = datetime.now().time()
  41. date = datetime.strptime(day, "%Y-%m-%d")
  42. # 人员
  43. user_row = db_user.get_user_info(db, user_id)
  44. dept_id = user_row.dept_id
  45. # 默认值
  46. data['users'] = {
  47. "user1": "-",
  48. "user2": "-",
  49. "user3": "-",
  50. "user4": "-"
  51. }
  52. # 当前用户的同一个部门的值班
  53. where = and_(DutyShift.shift_date == date, DutyShift.start_time < current_time)
  54. # where = and_(where, DutyShift.dept_id == dept_id)
  55. row = db.query(DutyShift).filter(where).first()
  56. if row is not None:
  57. shift_id = row.shift_id
  58. shift_status = row.shift_status
  59. handover_time = row.handover_time
  60. user_info = get_model_dict(row)
  61. user_info['user1'] = db_user.get_nick_name_by_id(db, user_info['leader_id'])
  62. user_info['user2'] = db_user.get_nick_name_by_id(db, user_info['primary_staff_id'])
  63. user_info['user3'] = db_user.get_nick_name_by_id(db, user_info['secondary_staff_id'])
  64. user_info['user4'] = db_user.get_nick_name_by_id(db, user_info['standby_staff_id'])
  65. data['users'] = user_info
  66. # 提醒事项
  67. where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '1', DutyNotify.shift_id == shift_id)
  68. rows = db.query(DutyNotify).filter(where).all()
  69. items = []
  70. for row in rows:
  71. items.append({
  72. "text": row.notify_content,
  73. "time": get_datetime_str(row.create_time)
  74. })
  75. data['remainds'] = items
  76. # 待办事项
  77. where = and_(DutyNotify.del_flag == '0', DutyNotify.notify_type == '2', DutyNotify.shift_id == shift_id)
  78. rows = db.query(DutyNotify).filter(where).all()
  79. items = []
  80. for row in rows:
  81. items.append({
  82. "text": row.notify_content,
  83. "time": get_datetime_str(row.create_time)
  84. })
  85. data['todos'] = items
  86. data['shift_id'] = shift_id
  87. data['shift_status'] = shift_status
  88. data['handover_time'] = get_datetime_str(handover_time)
  89. # 目前不知道有什么用
  90. data['days'] = []
  91. return {
  92. "code": 200,
  93. "msg": "查询成功",
  94. "data": data
  95. }
  96. except AppException as e:
  97. return {
  98. "code": e.code,
  99. "msg": e.msg
  100. }
  101. except Exception as e:
  102. traceback.print_exc()
  103. # 处理异常
  104. raise HTTPException(status_code=500, detail=str(e))
  105. # 暂时没用
  106. @router.get("/my_calendar_by_month")
  107. async def calendar_by_month(
  108. date: str = Query(None, description="月份"),
  109. db: Session = Depends(get_db),
  110. user_id = Depends(valid_access_token)
  111. ):
  112. the_year = datetime.now().year
  113. the_month = datetime.now().month
  114. if date is not None and date != '':
  115. arr = date.split("-")
  116. the_year = arr[0]
  117. the_month = arr[1]
  118. try:
  119. 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)
  120. where = and_(func.extract('year', DutyShift.shift_date) == the_year, func.extract('month', DutyShift.shift_date) == the_month)
  121. where = and_(where, user_where)
  122. rows = db.query(DutyShift.shift_date).distinct().filter(where).all()
  123. data = []
  124. for row in rows:
  125. data.append({
  126. "date": row.shift_date,
  127. "color": "a2d7f1"
  128. })
  129. return {
  130. "code": 200,
  131. "msg": "查询成功",
  132. "data": data
  133. }
  134. except AppException as e:
  135. return {
  136. "code": e.code,
  137. "msg": e.msg
  138. }
  139. except Exception as e:
  140. traceback.print_exc()
  141. # 处理异常
  142. raise HTTPException(status_code=500, detail=str(e))
  143. # 新增提醒或者待办
  144. @router.post("/add_notify")
  145. async def create_by_city_to_area(
  146. db: Session = Depends(get_db),
  147. body = Depends(remove_xss_json),
  148. user_id = Depends(valid_access_token)
  149. ):
  150. try:
  151. shift_id = body['shift_id']
  152. notify_type = body['notify_type']
  153. notify_content = body['notify_content']
  154. new_notify = DutyNotify(
  155. shift_id = shift_id,
  156. notify_type = notify_type,
  157. notify_content = notify_content,
  158. create_time = datetime.now(),
  159. del_flag = '0',
  160. recorded_by = user_id
  161. )
  162. db.add(new_notify)
  163. db.commit()
  164. db.refresh(new_notify)
  165. new_notify_id = new_notify.id
  166. return {
  167. "code": 200,
  168. "msg": "事项创建成功",
  169. "data": new_notify_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. # 交班
  181. @router.post("/handover")
  182. async def handover(
  183. db: Session = Depends(get_db),
  184. body = Depends(remove_xss_json),
  185. user_id = Depends(valid_access_token)
  186. ):
  187. try:
  188. shift_id = body['shift_id']
  189. where = and_(DutyShift.shift_id == shift_id)
  190. row = db.query(DutyShift).filter(where).first()
  191. if row is None:
  192. raise AppException("班次不存在")
  193. if row.shift_status == 1:
  194. raise AppException("班次已交班,不用重复操作")
  195. row.shift_status = 1
  196. row.handover_time = datetime.now()
  197. row.handover_user_id = user_id
  198. db.commit()
  199. return {
  200. "code": 200,
  201. "msg": "交班成功",
  202. "data": shift_id
  203. }
  204. except AppException as e:
  205. return {
  206. "code": e.code,
  207. "msg": e.msg
  208. }
  209. except Exception as e:
  210. traceback.print_exc()
  211. # 处理异常
  212. raise HTTPException(status_code=500, detail=str(e))
  213. # 值班表查询
  214. @router.get("/duty_book_by_area")
  215. async def duty_book_by_year_and(
  216. year: str,
  217. area: str,
  218. db: Session = Depends(get_db)
  219. ):
  220. try:
  221. data = []
  222. where = and_(DutyBook.del_flag == '0', DutyBook.year == year, DutyBook.area_code == area)
  223. rows = db.query(DutyBook).filter(where).order_by(DutyBook.month.asc()).all()
  224. for row in rows:
  225. file_url = ""
  226. file_row = db.query(DutyFile).filter(and_(DutyFile.del_flag == '0', DutyFile.from_scenario == 'duty_book', DutyFile.foreign_key == row.id)).first()
  227. if file_row is not None:
  228. file_url = file_row.storage_file_name
  229. data.append({
  230. "id": row.id,
  231. "name": get_month_text(row.month)+"月份",
  232. "name2": get_month_text(row.month)+"月份排班表.xlsx",
  233. "time": row.create_time.strftime("%m-%d %H:%M"),
  234. "url": file_url
  235. })
  236. return {
  237. "code": 200,
  238. "msg": "交班成功",
  239. "data": data
  240. }
  241. except AppException as e:
  242. return {
  243. "code": e.code,
  244. "msg": e.msg
  245. }
  246. except Exception as e:
  247. traceback.print_exc()
  248. # 处理异常
  249. raise HTTPException(status_code=500, detail=str(e))
  250. # 上传排班表
  251. @router.post("/upload_duty_book")
  252. async def upload_duty_book(
  253. db: Session = Depends(get_db),
  254. body = Depends(remove_xss_json),
  255. user_id = Depends(valid_access_token)
  256. ):
  257. try:
  258. dept_id = 0
  259. user_row = db.query(SysUser).filter(SysUser.user_id == user_id).first()
  260. dept_id = user_row.dept_id
  261. area = body['area']
  262. year = body['year']
  263. month = body['month']
  264. # 先导入附件
  265. # 附件
  266. if 'files' not in body:
  267. raise AppException(500, "请上传值班表")
  268. # 从1号开始
  269. date = datetime.strptime(year + "-" + month + "-01", "%Y-%m-%d")
  270. users = []
  271. fileName = body['files'][0]
  272. users = import_duty_book_from_file(int(year), int(month), date, fileName)
  273. if len(users) == 0:
  274. raise AppException(500, "无法获取值班人员")
  275. # 标记之前的导入已删除
  276. old_book_id = 0
  277. where = and_(DutyBook.del_flag == '0', DutyBook.year == year, DutyBook.area_code == area)
  278. row = db.query(DutyBook).filter(where).order_by(DutyBook.month.asc()).first()
  279. if row is not None:
  280. old_book_id = row.id
  281. row.del_flag = '2'
  282. db.commit()
  283. # 新建导入
  284. new_book = DutyBook(
  285. year = year, month = month, area_code = area,
  286. recorded_by = user_id, create_time = datetime.now(), del_flag = '0'
  287. )
  288. db.add(new_book)
  289. db.commit()
  290. db.refresh(new_book)
  291. new_book_id = new_book.id
  292. for (date, item) in users.items():
  293. onduty_leader = item['onduty_leader']
  294. onduty_user = item['onduty_user']
  295. new_shift = DutyShift(
  296. shift_date = date,
  297. # 目前只是值班一整天
  298. start_time = "00:00",
  299. end_time = "23:59",
  300. leader_id = 0,
  301. primary_staff_id = 0,
  302. onduty_leader = onduty_leader,
  303. onduty_user = onduty_user,
  304. # Excel没用到这两个字段
  305. secondary_staff_id = -1,
  306. standby_staff_id = -1,
  307. duty_type = "综合值班",
  308. shift_status = 0,
  309. handover_user_id = 0,
  310. handover_time = None,
  311. dept_id = -1, # 这个字段没用
  312. area_code = area,
  313. del_flag = '0',
  314. book_id = new_book_id
  315. )
  316. db.add(new_shift)
  317. db.commit()
  318. # 标记之前的值班信息已删除
  319. where = and_(DutyShift.del_flag == '0', DutyShift.book_id == old_book_id)
  320. db.query(DutyShift).filter(where).update({"del_flag": '2'})
  321. db.commit()
  322. new_file = DutyFile(
  323. file_name=fileName["name"],
  324. storage_file_name=fileName["url"],
  325. file_path=f'/data/upload/mergefile/uploads/{fileName["url"]}',
  326. file_size=os.path.getsize(f'/data/upload/mergefile/uploads/{fileName["url"]}'),
  327. foreign_key=str(new_book_id),
  328. from_scenario="duty_book",
  329. update_time=datetime.now(),
  330. create_time=datetime.now(),
  331. create_by=user_id,
  332. create_dept=dept_id,
  333. del_flag='0',
  334. status=0,
  335. )
  336. db.add(new_file)
  337. db.commit()
  338. db.refresh(new_file)
  339. return {
  340. "code": 200,
  341. "msg": "上传成功",
  342. "data": new_file.id
  343. }
  344. except AppException as e:
  345. return {
  346. "code": e.code,
  347. "msg": e.msg
  348. }
  349. except Exception as e:
  350. traceback.print_exc()
  351. # 处理异常
  352. raise HTTPException(status_code=500, detail=str(e))
  353. def import_duty_book_from_file(year: int, month: int, date: datetime, fileName: dict) -> dict:
  354. file_path = f'/data/upload/mergefile/uploads/{fileName["url"]}'
  355. wb = openpyxl.load_workbook(file_path)
  356. ws = wb.active
  357. rows = []
  358. for row in ws.iter_rows(values_only=True):
  359. rows.append(list(row))
  360. print(list(row))
  361. users = {}
  362. while date.month == month:
  363. day = datetime.strftime(date, "%m月%d日")
  364. for x in range(len(rows)):
  365. row = rows[x]
  366. for y in range(len(row)):
  367. cell = row[y]
  368. if cell == day:
  369. try:
  370. # 带班领导
  371. onduty_leader = rows[x+1][y]
  372. # 值班人员
  373. onduty_user = rows[x+2][y]
  374. if onduty_leader is None:
  375. raise AppException(500, "无法获取"+day+"的带班领导")
  376. if onduty_user is None:
  377. raise AppException(500, "无法获取"+day+"的值班人员")
  378. # date1 = date.strftime("%Y-%m-%d")
  379. users[date] = {"day": day, "onduty_leader": onduty_leader, "onduty_user": onduty_user}
  380. except Exception as e:
  381. raise AppException(500, "无法获取"+day+"的值班人员")
  382. break
  383. date = date + timedelta(days=1)
  384. return users