|
|
# -*- coding: utf-8 -*-
|
|
|
# @Time : 2023/8/8 14:49
|
|
|
# @Author : tx
|
|
|
# @File : drug.py
|
|
|
# @Description :
|
|
|
import base64
|
|
|
import datetime
|
|
|
import os
|
|
|
import uuid
|
|
|
from decimal import Decimal
|
|
|
from typing import List
|
|
|
import json
|
|
|
|
|
|
from fastapi import Request, APIRouter, Depends, UploadFile, File
|
|
|
from fastapi.encoders import jsonable_encoder
|
|
|
from starlette.responses import FileResponse
|
|
|
from tortoise.expressions import Q
|
|
|
from tortoise.functions import Function
|
|
|
from pypika import CustomFunction
|
|
|
|
|
|
from helper import respond_to, login_required
|
|
|
from helper.GaoPaiYi import GaoPaiYi
|
|
|
from helper.drug import open_update_expired_at, simple_drugs_except_info, drugs_list_info, milligram_to_gram
|
|
|
from helper.log import logger_wrapper
|
|
|
from helper.logger import logger
|
|
|
from models import Drug, Dictionary, DrugStateEnum, Template, Terminal, DrugUseStateEnum, DrugUseLog, User
|
|
|
from pydantic import BaseModel
|
|
|
from models.archive import Archive
|
|
|
from models.cabinet import Cabinet
|
|
|
|
|
|
from models.drawers import Drawer
|
|
|
from models.drug_relation_image import DrugRelationImage
|
|
|
from models.log import EnvironmentLogs
|
|
|
from transfer.standard import Standard
|
|
|
from transfer.basic import BasicStandard
|
|
|
|
|
|
router = APIRouter(prefix='/drug', dependencies=[Depends(login_required)])
|
|
|
# router = APIRouter(prefix='/drug')
|
|
|
|
|
|
class DrugRfids(BaseModel):
|
|
|
rfids: list
|
|
|
|
|
|
class ReturnForm(BaseModel):
|
|
|
# barcode: str
|
|
|
weight: Decimal = 0.0 # 余量
|
|
|
use_weight: Decimal = 0.0 # 用量
|
|
|
drawer_id: str = '' # 层id
|
|
|
cabinet_id: str = '' # 柜体id
|
|
|
is_empty: int = 0 # 1空瓶 0非空瓶
|
|
|
|
|
|
class EmptyBottleDisposal(BaseModel):
|
|
|
rfid: str
|
|
|
weight: int | None
|
|
|
open_date: str | None
|
|
|
|
|
|
class DrugUpdateRequest(BaseModel):
|
|
|
open_date: str = "" # 开封日期
|
|
|
weight: Decimal = 0.0 # 余量
|
|
|
use_weight: str | Decimal = 0.0 # 用量
|
|
|
rfid: str = ""
|
|
|
id: str = ""
|
|
|
|
|
|
class DrugDeleteRequest(BaseModel):
|
|
|
drug_ids: list
|
|
|
|
|
|
|
|
|
class ImageDeleteRequest(BaseModel):
|
|
|
image_ids: list
|
|
|
|
|
|
|
|
|
class ImageUploadRequest(BaseModel):
|
|
|
upload_list: list = []
|
|
|
|
|
|
|
|
|
|
|
|
class DrugUpdateExpired(BaseModel):
|
|
|
|
|
|
expired_at: str
|
|
|
rfid: str = ""
|
|
|
id: str = ""
|
|
|
|
|
|
class UpdateDrugRequest(BaseModel):
|
|
|
cabinet_id: str
|
|
|
receive_id: str | None # 移库人
|
|
|
|
|
|
|
|
|
class JsonExtract(Function):
|
|
|
database_func=CustomFunction('JSON_EXTRACT', ['field', 'value'])
|
|
|
|
|
|
@router.get('/take_out', summary='药剂领用列表查询')
|
|
|
async def index(request: Request, cabinet_id: str = '', drug_name: str = '', page_no: int = 1, page_size: int = 20):
|
|
|
"""
|
|
|
药剂领用列表查询
|
|
|
:return:
|
|
|
"""
|
|
|
query = Drug.filter(state=DrugStateEnum.IN, template__archive_id=request.state.archive_id).order_by('-created_at')
|
|
|
if cabinet_id:
|
|
|
query = query.filter(cabinet_id=cabinet_id)
|
|
|
print(f'drug_name: {drug_name}')
|
|
|
if drug_name:
|
|
|
query = query.filter(Q(dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
|
|
|
|
|
|
total_count = await query.count()
|
|
|
offset = (page_no - 1) * page_size
|
|
|
drugs = await query.offset(offset).limit(page_size).all()
|
|
|
|
|
|
archive_id = request.state.archive_id
|
|
|
archive_obj = await Archive.get_or_none(id=archive_id)
|
|
|
archive_name = archive_obj.name if archive_obj else ""
|
|
|
|
|
|
result = list()
|
|
|
for drug_obj in drugs:
|
|
|
data = {
|
|
|
"drug_id": drug_obj.id,
|
|
|
"rfid": drug_obj.rfid,
|
|
|
"hole": drug_obj.hole,
|
|
|
"cabinet_id": drug_obj.cabinet_id,
|
|
|
"drawer_id": drug_obj.drawer_id,
|
|
|
"board_id": drug_obj.board_id,
|
|
|
"position": drug_obj.position,
|
|
|
"expired_at": drug_obj.expired_at,
|
|
|
"remain_gross_weight": await drug_obj.format_weight(),
|
|
|
"display_weight": await drug_obj.format_weight(),
|
|
|
"drug_info": drug_obj.fill_json_content,
|
|
|
"state": drug_obj.state,
|
|
|
"open_date": drug_obj.open_date
|
|
|
}
|
|
|
if archive_name == "耗材":
|
|
|
data.update({
|
|
|
"remain_count": int(drug_obj.attribute("total_count")) - drug_obj.total_use_weight if drug_obj.attribute("total_count") else "-"
|
|
|
})
|
|
|
result.append(data)
|
|
|
|
|
|
return respond_to(code=200, data=dict(count=total_count, list=result))
|
|
|
|
|
|
|
|
|
@router.post('/except', summary='RFID药剂异常信息')
|
|
|
async def index(request: DrugRfids):
|
|
|
"""
|
|
|
获取RFID药剂异常信息
|
|
|
:return:
|
|
|
"""
|
|
|
result = list()
|
|
|
drugs = await Drug.filter(rfid__in=request.rfids).all()
|
|
|
for drug in drugs:
|
|
|
data = await simple_drugs_except_info(drug)
|
|
|
data["rfid"] = drug.rfid
|
|
|
result.append(data)
|
|
|
# 传入rfid与data所有rfid比较,差集就是非法标签
|
|
|
post_rfid = set(request.rfids)
|
|
|
effective_rfid = set([i["rfid"] for i in result])
|
|
|
diff_rfid = post_rfid - effective_rfid
|
|
|
if diff_rfid:
|
|
|
result.extend([{
|
|
|
"rfid": rfid,
|
|
|
"is_rfid_except": True,
|
|
|
"sound": True,
|
|
|
"message": "非法标签",
|
|
|
"state": 0,
|
|
|
} for rfid in diff_rfid])
|
|
|
return respond_to(code=200, desc="获取RFID药剂信息成功", data=result)
|
|
|
|
|
|
|
|
|
@router.post('', summary='RFID药剂详情')
|
|
|
async def index(request: Request, body: DrugRfids):
|
|
|
"""
|
|
|
获取RFID药剂信息 药剂信息详情
|
|
|
:return:
|
|
|
"""
|
|
|
drugs = list()
|
|
|
for rfid in body.rfids:
|
|
|
# rfid = bytes.hex(bytes.fromhex(rfid)[::-1]) if len(rfid) > 10 else rfid
|
|
|
drug_obj = await Drug.filter(Q(rfid=rfid) | Q(barcode=rfid)).prefetch_related('template__archive').prefetch_related('cabinet__terminal').first()
|
|
|
template_archive_obj = await Template.filter(id=drug_obj.template_id).prefetch_related('archive').first() if drug_obj and drug_obj.template_id else None
|
|
|
print(("drug_obj====", drug_obj))
|
|
|
print(("template_archive_obj====", template_archive_obj))
|
|
|
if drug_obj is None or template_archive_obj is None or str(template_archive_obj.archive_id) != str(request.state.archive_id):
|
|
|
drugs.append({
|
|
|
"drugs_except_info": {
|
|
|
"sound": False,
|
|
|
"message": "非法标签",
|
|
|
"state": 0,
|
|
|
},
|
|
|
"rfid_drug": {rfid: f"[{rfid}]未知药剂"}
|
|
|
})
|
|
|
continue
|
|
|
result = jsonable_encoder(drug_obj)
|
|
|
|
|
|
data = await simple_drugs_except_info(drug_obj)
|
|
|
|
|
|
drug_info = await drug_obj.attribute_drug_info()
|
|
|
parse_fill_json_content = await drug_obj.parse_fill_json_content()
|
|
|
parse_fill_json_content.update({f'余重': f'{milligram_to_gram(drug_obj.remain_gross_weight)}'})
|
|
|
|
|
|
return_require_weigh = template_archive_obj.archive.params.get("return_require_weigh", '')
|
|
|
|
|
|
user_obj = await User.get_or_none(id=drug_obj.last_receive_id).values("id", "name") if drug_obj.last_receive_id else ''
|
|
|
result.update({
|
|
|
"drugs_except_info": data,
|
|
|
"fill_json_content": parse_fill_json_content,
|
|
|
"rfid_drug": {drug_obj.rfid: f"[{drug_obj.rfid}]" + ",".join(list(map(lambda x:str(x), drug_info.values())))},
|
|
|
"return_require_weigh": return_require_weigh,
|
|
|
"last_user": user_obj.get("name") if user_obj else '',
|
|
|
"cabinet_label": drug_obj.cabinet.label if drug_obj.cabinet else "",
|
|
|
"cabinet_location": drug_obj.cabinet.location if drug_obj.cabinet else "",
|
|
|
"terminal": drug_obj.cabinet.terminal.name if drug_obj.cabinet and drug_obj.cabinet.terminal else None,
|
|
|
"position": drug_obj.position,
|
|
|
"unit_code": drug_obj.attribute("unit_code", ""),
|
|
|
"total_count": drug_obj.attribute("total_count"),
|
|
|
"total_use_weight": drug_obj.total_use_weight,
|
|
|
})
|
|
|
drugs.append(result)
|
|
|
return respond_to(code=200, desc="获取RFID药剂信息成功", data=drugs)
|
|
|
|
|
|
|
|
|
|
|
|
@router.put('/receive/{code}', summary='药剂领用')
|
|
|
async def update(request: Request, code: str, use_count: int = -1):
|
|
|
"""
|
|
|
药剂领用
|
|
|
耗材领用 输入使用数量,余量为0则空 总量为fill_json_content中import_count,总用量存储在total_use_weight中
|
|
|
:return:
|
|
|
"""
|
|
|
# code = bytes.hex(bytes.fromhex(code)[::-1]) if len(code) > 10 else code
|
|
|
drug_obj = await Drug.filter(Q(rfid=code) | Q(barcode=code)).prefetch_related("cabinet", "template__archive").first()
|
|
|
if drug_obj is None:
|
|
|
return respond_to(code=404, desc='非法标签')
|
|
|
template_name = drug_obj.template.name
|
|
|
if not drug_obj:
|
|
|
return respond_to(code=404, desc='条码不存在')
|
|
|
if drug_obj.state == DrugStateEnum.OUT:
|
|
|
return respond_to(code=403, desc='条码不在库')
|
|
|
if drug_obj.state == DrugStateEnum.EMPTY:
|
|
|
return respond_to(code=403, desc='条码已空瓶')
|
|
|
if str(drug_obj.template.archive_id) != str(request.state.archive_id):
|
|
|
return respond_to(code=403, desc='条码不在当前大类')
|
|
|
|
|
|
current_user = request.state.current_user
|
|
|
|
|
|
users = request.state.users
|
|
|
if template_name == "耗材":
|
|
|
total_use_count = drug_obj.total_use_weight if drug_obj.total_use_weight else 0
|
|
|
if use_count > -1 and (total_use_count + use_count >= int(drug_obj.attribute("total_count"))):
|
|
|
print("用完", total_use_count, use_count)
|
|
|
drug_obj.state = DrugStateEnum.EMPTY
|
|
|
drug_obj.total_use_weight = drug_obj.attribute("total_count")
|
|
|
elif use_count > -1:
|
|
|
drug_obj.total_use_weight = total_use_count + use_count
|
|
|
else:
|
|
|
drug_obj.state = DrugStateEnum.OUT
|
|
|
|
|
|
drug_obj.last_receive_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
drug_obj.last_receive_id = current_user.id
|
|
|
|
|
|
await drug_obj.save()
|
|
|
# 流转日志保存
|
|
|
drug_use_dict = {
|
|
|
"drug": drug_obj,
|
|
|
"state": DrugUseStateEnum.TAKE,
|
|
|
"user_id": current_user.id,
|
|
|
"peer_ids": ",".join(users[1:]), # 陪同人id
|
|
|
"users": await User.parse_id_user(users),
|
|
|
"terminal_id": drug_obj.cabinet.terminal_id, # 终端id
|
|
|
"cabinet_id": drug_obj.cabinet.id if drug_obj.cabinet else None,
|
|
|
"drawer_id": drug_obj.drawer_id if drug_obj.drawer else None,
|
|
|
"drawer_board_id": drug_obj.drawer_board_id if drug_obj.drawer_board else None,
|
|
|
"hole": drug_obj.hole,
|
|
|
"position": drug_obj.position,
|
|
|
"alerted": False, # 是否报警 领用称重
|
|
|
"weight": drug_obj.remain_gross_weight,
|
|
|
}
|
|
|
if template_name == "耗材" and use_count > -1:
|
|
|
drug_use_dict.update({
|
|
|
"use_weight": use_count
|
|
|
})
|
|
|
|
|
|
|
|
|
drug_update_dict = {}
|
|
|
# 首次领用即空瓶逻辑
|
|
|
first_will_empty = await drug_obj.parse_archive_params("first_will_empty")
|
|
|
if first_will_empty:
|
|
|
drug_use_dict.update({
|
|
|
"state": DrugUseStateEnum.EMPTY,
|
|
|
"weight": 0,
|
|
|
"use_weight": drug_obj.remain_gross_weight,
|
|
|
})
|
|
|
# 领用即空瓶 药剂状态更改
|
|
|
drug_update_dict.update({
|
|
|
"state": DrugStateEnum.EMPTY,
|
|
|
"remain_gross_weight": 0,
|
|
|
})
|
|
|
await drug_obj.update_from_dict(drug_update_dict)
|
|
|
await drug_obj.save()
|
|
|
await DrugUseLog().create(**drug_use_dict)
|
|
|
|
|
|
# 药剂数据封装返回前端
|
|
|
result = jsonable_encoder(drug_obj)
|
|
|
drug_info = await drug_obj.attribute_drug_info()
|
|
|
parse_fill_json_content = await drug_obj.parse_fill_json_content()
|
|
|
result.update({
|
|
|
"drug_info": drug_info, # k1-k6数据
|
|
|
"fill_json_content": parse_fill_json_content,
|
|
|
"rfid_drug": {drug_obj.rfid: f"[{drug_obj.rfid}]" + ",".join(list(map(lambda x:str(x), drug_info.values()))) + "," +
|
|
|
f"{drug_obj.remain_gross_weight}"},
|
|
|
# "display_remain": drug_obj.change_display_remain() # 余量展示数据
|
|
|
})
|
|
|
return respond_to(code=200, desc="领用成功", data=result)
|
|
|
|
|
|
|
|
|
@router.get('/put_in', summary='待归还列表')
|
|
|
async def index(request: Request, cabinet_id: str = '', drug_name: str = '', page_no: int = 1, page_size: int = 10):
|
|
|
"""
|
|
|
获取当前用户待归还清单
|
|
|
:return:
|
|
|
"""
|
|
|
current_user = request.state.current_user
|
|
|
|
|
|
# 当前柜体待归还清单
|
|
|
query = Drug.filter(last_receive_id=current_user.id, state=2, template__archive_id=request.state.archive_id)
|
|
|
if cabinet_id:
|
|
|
query = query.filter(cabinet_id=cabinet_id)
|
|
|
if drug_name:
|
|
|
query = query.filter(Q(dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
|
|
|
total_count = await query.count()
|
|
|
offset = (page_no - 1) * page_size
|
|
|
drugs = await query.offset(offset).limit(page_size).all()
|
|
|
result = list()
|
|
|
for drug_obj in drugs:
|
|
|
receive_user_obj = await User.get_or_none(id=drug_obj.last_receive_id)
|
|
|
data = {
|
|
|
"drug_id": drug_obj.id,
|
|
|
"rfid": drug_obj.rfid,
|
|
|
"hole": drug_obj.hole,
|
|
|
"cabinet_id": drug_obj.cabinet_id if drug_obj.cabinet_id else None,
|
|
|
"drawer_id": drug_obj.drawer_id,
|
|
|
"board_id": drug_obj.board_id,
|
|
|
"position": drug_obj.position,
|
|
|
"expired_at": drug_obj.expired_at,
|
|
|
"remain_gross_weight": await drug_obj.format_weight(),
|
|
|
"display_weight": await drug_obj.format_weight(),
|
|
|
"last_receive_at": drug_obj.last_receive_at,
|
|
|
"last_receive_user": receive_user_obj.name if receive_user_obj else '',
|
|
|
"drug_info": await drug_obj.parse_fill_json_content()
|
|
|
}
|
|
|
result.append(data)
|
|
|
return respond_to(data=dict(count=total_count, drugs=result))
|
|
|
|
|
|
|
|
|
@router.put('/return/{code}', summary='药剂归还')
|
|
|
async def update(request: Request, code: str, keyword: ReturnForm):
|
|
|
"""
|
|
|
药剂归还
|
|
|
药剂扫码后填入用量/余量,归还成功
|
|
|
:param code: 药剂条码
|
|
|
:param post:
|
|
|
:return:
|
|
|
"""
|
|
|
# 如果调用保存已经保存过用量数据,则不再进行保存
|
|
|
# code = bytes.hex(bytes.fromhex(code)[::-1]) if len(code) > 10 else code
|
|
|
# print("code=============",code)
|
|
|
drug_obj = await Drug.get_or_none(Q(barcode=code) | Q(rfid=code)).prefetch_related('template', 'dictionary')
|
|
|
if not drug_obj:
|
|
|
return respond_to(code=404, desc="药剂未找到")
|
|
|
if str(drug_obj.template.archive_id) != str(request.state.archive_id):
|
|
|
return respond_to(code=403, desc='药剂不在当前大类')
|
|
|
|
|
|
if keyword.weight:
|
|
|
# 余量转用量,更新用量
|
|
|
mill_weight = drug_obj.remain_gross_weight - keyword.weight
|
|
|
drug_obj.total_use_weight = drug_obj.total_use_weight + mill_weight
|
|
|
# drug_obj.remain_gross_weight = keyword.weight
|
|
|
drug_obj.last_use_weight = float(mill_weight)
|
|
|
elif keyword.use_weight:
|
|
|
mill_weight = keyword.use_weight
|
|
|
drug_obj.total_use_weight = drug_obj.total_use_weight + mill_weight
|
|
|
# drug_obj.remain_gross_weight = drug_obj.remain_gross_weight - keyword.use_weight
|
|
|
drug_obj.last_use_weight = float(mill_weight)
|
|
|
|
|
|
# 位置更新
|
|
|
if keyword.drawer_id or keyword.cabinet_id:
|
|
|
position_str = ""
|
|
|
if keyword.cabinet_id:
|
|
|
cabinet = await Cabinet.get(id=keyword.cabinet_id)
|
|
|
drug_obj.cabinet = cabinet
|
|
|
position_str = f"{cabinet.label}"
|
|
|
if keyword.drawer_id:
|
|
|
drawer_obj = await Drawer.get(id=keyword.drawer_id).prefetch_related("cabinet")
|
|
|
drug_obj.drawer = drawer_obj
|
|
|
cabinet = await drawer_obj.cabinet
|
|
|
position_str = f"{cabinet.label}-{drawer_obj.label}"
|
|
|
drug_obj.position = position_str
|
|
|
|
|
|
cabinet_obj = await Cabinet.get(id=drug_obj.cabinet_id) if drug_obj.cabinet else None
|
|
|
|
|
|
users = request.state.current_user
|
|
|
if keyword.is_empty:
|
|
|
standard = Standard(request.state.users)
|
|
|
await standard.empty(code, 0, cabinet_obj.terminal_id)
|
|
|
open_date=drug_obj.open_date
|
|
|
if open_date:
|
|
|
drug_obj.open_date = datetime.datetime.now()
|
|
|
await drug_obj.save(update_fields=["open_date"])
|
|
|
return respond_to(desc="归还完成", data="空瓶")
|
|
|
|
|
|
drug_obj.last_return_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
open_date = drug_obj.open_date
|
|
|
if not open_date:
|
|
|
drug_obj.open_date = datetime.datetime.now()
|
|
|
drug_obj.last_return_id = users.id
|
|
|
await drug_obj.save()
|
|
|
|
|
|
basic_standard = BasicStandard()
|
|
|
standard = Standard(request.state.users)
|
|
|
await basic_standard.basic_put_in(standard, code, cabinet_id=drug_obj.cabinet_id, line_no=0, hole=None)
|
|
|
|
|
|
return respond_to(desc="归还完成")
|
|
|
|
|
|
|
|
|
|
|
|
@router.post('/empty', summary='试剂置为空瓶')
|
|
|
async def empty_bottle_disposal(request: Request, post: EmptyBottleDisposal):
|
|
|
"""
|
|
|
试剂置为空瓶
|
|
|
:param request: Request请求头信息
|
|
|
:param post: 空瓶信息的请求体
|
|
|
:return:
|
|
|
"""
|
|
|
users = request.state.users
|
|
|
|
|
|
rfid = post.rfid
|
|
|
drug = await Drug.get_or_none(Q(barcode=rfid) | Q(rfid=rfid)).prefetch_related("cabinet")
|
|
|
|
|
|
open_date = post.open_date
|
|
|
standard = Standard(users)
|
|
|
if open_date:
|
|
|
drug.open_date = open_date
|
|
|
await drug.save()
|
|
|
await standard.empty(rfid, 0, drug.cabinet.terminal_id)
|
|
|
return respond_to()
|
|
|
|
|
|
|
|
|
@router.post('/weight', summary="药剂用量或余量更新")
|
|
|
async def update(keyword: DrugUpdateRequest):
|
|
|
"""
|
|
|
药剂用量或余量更新
|
|
|
接收id或rfid都可以更新重量
|
|
|
余量与用量二选一,只有一个有值
|
|
|
:param keyword: 包含更新信息的请求体
|
|
|
:return:
|
|
|
"""
|
|
|
print("open_date", keyword.open_date)
|
|
|
rfid = keyword.rfid if keyword.rfid else ""
|
|
|
query_param = {"id": keyword.id} if keyword.id else {"rfid": rfid}
|
|
|
check_drug_obj = await Drug.get(**query_param)
|
|
|
if not check_drug_obj:
|
|
|
return respond_to(404, desc="药剂不存在")
|
|
|
|
|
|
drug_obj = await Drug.get(**query_param).prefetch_related("template")
|
|
|
if keyword.weight:
|
|
|
# 余量转用量,更新用量
|
|
|
mill_weight = drug_obj.remain_gross_weight - keyword.weight if drug_obj.remain_gross_weight else 0
|
|
|
await drug_obj.update_last_use_weight(weight=float(mill_weight))
|
|
|
drug_obj.remain_gross_weight = keyword.weight
|
|
|
await drug_obj.save()
|
|
|
elif keyword.use_weight:
|
|
|
mill_weight = keyword.use_weight if keyword.use_weight and keyword.use_weight != "NaN" else 0
|
|
|
await drug_obj.update_last_use_weight(weight=float(mill_weight))
|
|
|
if keyword.open_date:
|
|
|
if not drug_obj.open_date:
|
|
|
drug_obj.open_date = keyword.open_date
|
|
|
template_obj = drug_obj.template
|
|
|
new_expired_at = open_update_expired_at(drug_obj, template_obj, keyword.open_date)
|
|
|
if new_expired_at:
|
|
|
drug_obj.expired_at = new_expired_at
|
|
|
await drug_obj.save()
|
|
|
return respond_to(code=200, desc="重量更新成功")
|
|
|
|
|
|
|
|
|
@router.get('/data/list', summary='试剂数据 - 列表查询')
|
|
|
async def data_list(request: Request, state: int = -1, drug_type='', cabinet_id: str = '', drug_name: str = '', page_no: int = 1, page_size: int = 20):
|
|
|
"""
|
|
|
试剂数据 - 列表查询
|
|
|
:return:
|
|
|
"""
|
|
|
query = Drug.filter(template__archive_id=request.state.archive_id).order_by('-storage_at')
|
|
|
if state > -1:
|
|
|
query = query.filter(state=state)
|
|
|
if cabinet_id:
|
|
|
query = query.filter(cabinet_id=cabinet_id)
|
|
|
if drug_type:
|
|
|
query = query.filter(drug_type=drug_type)
|
|
|
|
|
|
if drug_name:
|
|
|
annotate = {}
|
|
|
annotate['json_batch_no'] = JsonExtract('fill_json_content', '$.cas_number')
|
|
|
query = query.annotate(**annotate).filter(
|
|
|
Q(json_batch_no__contains=drug_name) | Q(fill_json_content__filter={"unit_code": drug_name}) | Q(
|
|
|
dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
|
|
|
# query = query.filter(Q(dictionary__k1__contains=drug_name) | Q(dictionary__k2__contains=drug_name))
|
|
|
|
|
|
total_count = await query.count()
|
|
|
offset = (page_no - 1) * page_size
|
|
|
drugs = await query.prefetch_related("dictionary", "template__archive").offset(offset).limit(page_size)
|
|
|
|
|
|
result = list()
|
|
|
for drug_obj in drugs:
|
|
|
data = {
|
|
|
"drug_id": drug_obj.id,
|
|
|
"archive_name": drug_obj.template.archive.name,
|
|
|
"storage_at": drug_obj.storage_at,
|
|
|
"cas": drug_obj.attribute("cas_number"),
|
|
|
"remain_gross_weight": await drug_obj.format_weight(),
|
|
|
"rfid": drug_obj.rfid,
|
|
|
"expired_at": drug_obj.expired_at,
|
|
|
"state": drug_obj.state,
|
|
|
"last_user": await drug_obj.attribute_last_user(),
|
|
|
"position": drug_obj.position,
|
|
|
"drug_info": await drug_obj.parse_fill_json_content(False),
|
|
|
"dictionary_id": drug_obj.dictionary_id,
|
|
|
"unit_code": drug_obj.fill_json_content["unit_code"] if 'unit_code' in drug_obj.fill_json_content else '-',
|
|
|
"open_date": drug_obj.open_date, # 开瓶日期
|
|
|
"manufacturer": drug_obj.attribute("cs"), # 生产厂商
|
|
|
"produce_date": drug_obj.attribute("produce_date"), # 生产日期
|
|
|
"ph": drug_obj.attribute("ph"), # 批号
|
|
|
}
|
|
|
# 盒装药剂药剂信息
|
|
|
if drug_obj.drug_type == "box":
|
|
|
box_item_info = await drug_obj.attribute_box_item_info()
|
|
|
data.update({
|
|
|
"drug_info": await drug_obj.attribute_drug_info(),
|
|
|
**box_item_info,
|
|
|
})
|
|
|
if data.get("archive_name") == "耗材":
|
|
|
data.update({
|
|
|
"remain_count": int(drug_obj.attribute("total_count")) - drug_obj.total_use_weight if drug_obj.attribute("total_count") else "-" # 余量
|
|
|
})
|
|
|
result.append(data)
|
|
|
return respond_to(200, data=dict(count=total_count, drugs=result))
|
|
|
|
|
|
|
|
|
|
|
|
@router.get('/data/flowRecord', summary='试剂数据 - 流转记录')
|
|
|
async def data_flow_record(request: Request, drug_id: str = '', page_no: int = 1, page_size: int = 20):
|
|
|
"""
|
|
|
试剂数据 - 流转记录
|
|
|
:return:
|
|
|
"""
|
|
|
offset = (page_no - 1) * page_size
|
|
|
query = DrugUseLog.filter(drug_id=drug_id)
|
|
|
count = await query.count()
|
|
|
drug_use_log_list = await query.prefetch_related('drug').offset(offset).limit(page_size).order_by('-created_at')
|
|
|
result = list()
|
|
|
for log in drug_use_log_list:
|
|
|
|
|
|
if log.state in [1, 3]:
|
|
|
use_weight = log.use_weight
|
|
|
finally_use_weight = "" if not use_weight and log.state != DrugUseStateEnum.PUT else use_weight
|
|
|
else:
|
|
|
finally_use_weight = ''
|
|
|
# weight > 1000 转换为g 保留一位小数否则返回mg
|
|
|
weight = float(log.weight) if log.weight else 0
|
|
|
if weight > 1000:
|
|
|
weight_str = f"{milligram_to_gram(log.weight)}g"
|
|
|
else:
|
|
|
weight_str = f"{log.weight}mg" if log.weight is not None else "-"
|
|
|
finally_use_weight_str = log.parse_use_weight(finally_use_weight)
|
|
|
print("finally_use_weight_str", finally_use_weight_str)
|
|
|
result.append({
|
|
|
**jsonable_encoder(log),
|
|
|
"drug_info": await log.drug.attribute_drug_info(),
|
|
|
"weight": weight_str,
|
|
|
"use_weight": finally_use_weight_str
|
|
|
})
|
|
|
return respond_to(data=dict(count=count, data=result))
|
|
|
|
|
|
|
|
|
@router.delete('/data/drugDelete', summary='试剂数据 - 试剂删除')
|
|
|
@logger_wrapper
|
|
|
async def drug_delete(request: Request, body: DrugDeleteRequest):
|
|
|
"""
|
|
|
试剂数据 - 试剂删除
|
|
|
:return:
|
|
|
"""
|
|
|
if len(body.drug_ids) == 0:
|
|
|
return respond_to(code=403, desc='请选择试剂')
|
|
|
await Drug.filter(id__in=body.drug_ids).delete()
|
|
|
return respond_to(desc='删除成功')
|
|
|
|
|
|
|
|
|
@router.put('/expired_at', summary='药剂信息修改')
|
|
|
@logger_wrapper
|
|
|
async def update(keyword: DrugUpdateExpired):
|
|
|
"""
|
|
|
药剂信息过期时间修改
|
|
|
:param id: 用户药剂模板条目id
|
|
|
:param keyword:
|
|
|
:return:
|
|
|
"""
|
|
|
rfid = keyword.rfid if keyword.rfid else ""
|
|
|
query_param = {"id": keyword.id} if keyword.id else {"rfid": rfid}
|
|
|
drug_obj = await Drug.get(**query_param)
|
|
|
drug_obj.expired_at = keyword.expired_at
|
|
|
await drug_obj.save()
|
|
|
return respond_to(code=200, desc="更新成功")
|
|
|
|
|
|
|
|
|
@router.put('/move/{code}', summary='药剂移库')
|
|
|
async def update(request: Request, code: str, keyword: UpdateDrugRequest):
|
|
|
"""
|
|
|
药剂移库
|
|
|
:return:
|
|
|
"""
|
|
|
cabinet_id = keyword.cabinet_id
|
|
|
cabinet_obj = await Cabinet.get_or_none(id=cabinet_id)
|
|
|
if not cabinet_obj:
|
|
|
return respond_to(code=404, desc='柜体不存在')
|
|
|
position = cabinet_obj.label
|
|
|
|
|
|
drug_obj = await Drug.filter(Q(rfid=code) | Q(barcode=code)).prefetch_related("cabinet", "template__archive").first()
|
|
|
if not drug_obj:
|
|
|
return respond_to(code=404, desc='药剂条码不存在')
|
|
|
if drug_obj.state == DrugStateEnum.OUT:
|
|
|
return respond_to(code=403, desc='药剂不在库')
|
|
|
if drug_obj.state == DrugStateEnum.EMPTY:
|
|
|
return respond_to(code=403, desc='药剂已空瓶')
|
|
|
if str(drug_obj.template.archive_id) != str(request.state.archive_id):
|
|
|
return respond_to(code=403, desc='药剂不在当前大类')
|
|
|
|
|
|
# 移库人
|
|
|
receive_id = keyword.receive_id
|
|
|
|
|
|
drug_obj.state = DrugStateEnum.OUT
|
|
|
|
|
|
drug_obj.last_receive_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
|
drug_obj.last_receive_id = receive_id
|
|
|
|
|
|
drug_obj.cabinet_id = cabinet_id
|
|
|
drug_obj.drawer_id = None
|
|
|
drug_obj.drawer_board_id = None
|
|
|
drug_obj.hole = None
|
|
|
drug_obj.position = position
|
|
|
|
|
|
await drug_obj.save()
|
|
|
users = [receive_id]
|
|
|
# 流转日志保存
|
|
|
drug_use_dict = {
|
|
|
"drug": drug_obj,
|
|
|
"state": DrugUseStateEnum.TAKE,
|
|
|
"user_id": receive_id,
|
|
|
"peer_ids": ",".join(users[1:]), # 陪同人id
|
|
|
"users": await User.parse_id_user(users),
|
|
|
"terminal_id": cabinet_obj.terminal_id, # 终端id
|
|
|
"cabinet_id": cabinet_id,
|
|
|
"position": position,
|
|
|
"alerted": False, # 是否报警 领用称重
|
|
|
"weight": drug_obj.remain_gross_weight,
|
|
|
}
|
|
|
await DrugUseLog().create(**drug_use_dict)
|
|
|
|
|
|
# 药剂数据封装返回前端
|
|
|
result = jsonable_encoder(drug_obj)
|
|
|
drug_info = await drug_obj.attribute_drug_info()
|
|
|
parse_fill_json_content = await drug_obj.parse_fill_json_content()
|
|
|
result.update({
|
|
|
"drug_info": drug_info, # k1-k6数据
|
|
|
"fill_json_content": parse_fill_json_content,
|
|
|
"rfid_drug": {drug_obj.rfid: f"[{drug_obj.rfid}]" + ",".join(list(map(lambda x:str(x), drug_info.values()))) + "," +
|
|
|
f"{drug_obj.remain_gross_weight}"},
|
|
|
# "display_remain": drug_obj.change_display_remain() # 余量展示数据
|
|
|
})
|
|
|
return respond_to(code=200, desc="完成", data=result)
|
|
|
|
|
|
|
|
|
# 高拍仪拍照
|
|
|
@router.get("/use_gaopaiyi")
|
|
|
async def use_gaopaiyi(drug_id: str = '', dictionary_id: str = ''):
|
|
|
pic_data = GaoPaiYi().getPic()
|
|
|
if pic_data['code'] == 0:
|
|
|
# 根据条码查询试剂信息
|
|
|
drug_info = await Drug.get_or_none(id=drug_id)
|
|
|
if not drug_info:
|
|
|
return respond_to(code=404, desc='药剂不存在')
|
|
|
obj = {
|
|
|
"drug_id": drug_id if drug_id else None,
|
|
|
"dictionary_id": dictionary_id if dictionary_id else None,
|
|
|
"pic_url": pic_data['path'],
|
|
|
"is_add": 0,
|
|
|
}
|
|
|
await DrugRelationImage().create(**obj)
|
|
|
return respond_to(code=200, desc="高拍仪拍照成功", data=pic_data['path'])
|
|
|
else:
|
|
|
return respond_to(code=400, desc="高拍仪拍照失败", data=pic_data['msg'])
|
|
|
|
|
|
|
|
|
# 获取药剂图片列表
|
|
|
@router.get("/get_drug_image")
|
|
|
async def get_medicament_image(drug_id: str = '', dictionary_id: str = '', is_add: int = 1):
|
|
|
query = DrugRelationImage().filter(is_add=is_add)
|
|
|
# 药剂类别
|
|
|
if drug_id:
|
|
|
query = query.filter(drug_id=drug_id)
|
|
|
if dictionary_id:
|
|
|
query = query.filter(dictionary_id=dictionary_id)
|
|
|
|
|
|
count = await query.count()
|
|
|
data_list = await query.all()
|
|
|
return respond_to(data=dict(count=count, data=data_list))
|
|
|
|
|
|
|
|
|
# 删除药剂图片
|
|
|
@router.delete("/del_drug_image")
|
|
|
async def del_medicament_image(body: ImageDeleteRequest):
|
|
|
if len(body.image_ids) == 0:
|
|
|
return respond_to(code=403, desc='请选择图片')
|
|
|
await DrugRelationImage.filter(id__in=body.image_ids).delete()
|
|
|
return respond_to(desc='删除成功')
|
|
|
|
|
|
|
|
|
@router.get("/get_img_info/{img_path}")
|
|
|
def get_drug_img(img_path):
|
|
|
print(os.path.join(os.getcwd(), "static", "msds"))
|
|
|
file_path = os.path.join(GaoPaiYi().path, img_path)
|
|
|
return FileResponse(file_path)
|
|
|
|
|
|
@router.get("/get_img_info1/{img_path}")
|
|
|
def get_drug_img1(img_path):
|
|
|
path =os.path.join(os.getcwd(), "static", "msds")
|
|
|
file_path = os.path.join(path, img_path)
|
|
|
return FileResponse(file_path)
|
|
|
|
|
|
|
|
|
@router.get("/download_imgs")
|
|
|
def download_drug_imgs(img_paths: List[str]):
|
|
|
base64_files = [] # 存放多个文件的 Base64 编码
|
|
|
|
|
|
for img_path in img_paths:
|
|
|
file_path = os.path.join(GaoPaiYi().path, img_path)
|
|
|
|
|
|
with open(file_path, "rb") as file:
|
|
|
file_data = file.read()
|
|
|
base64_data = base64.b64encode(file_data).decode("utf-8")
|
|
|
|
|
|
base64_files.append(base64_data)
|
|
|
return respond_to(data=base64_files)
|
|
|
|
|
|
# 图片上传接口
|
|
|
@router.post("/save_drug_img")
|
|
|
async def save_drug_img_info( upload_list: list, file: UploadFile = File(...)):
|
|
|
"""
|
|
|
文件上传保存
|
|
|
:param upload_list:
|
|
|
:param file:
|
|
|
:return:
|
|
|
"""
|
|
|
# 保存文件
|
|
|
gaopaiyi_obj = GaoPaiYi()
|
|
|
img_path = f"{str(uuid.uuid4())}.jpg"
|
|
|
with open(os.path.join(gaopaiyi_obj.path, img_path), "wb") as f:
|
|
|
f.write(await file.read())
|
|
|
content = json.loads(upload_list[0])
|
|
|
# 添加关联关系
|
|
|
for upload_item in content:
|
|
|
dictionary_id = upload_item.get("dictionary_id")
|
|
|
drug_id = upload_item.get("drug_id")
|
|
|
|
|
|
# 根据条码查询试剂信息
|
|
|
drug_info = await Drug.get_or_none(id=drug_id)
|
|
|
dictionary_info = await Dictionary.get_or_none(id=dictionary_id)
|
|
|
|
|
|
if not drug_info and not dictionary_info:
|
|
|
return respond_to(code=400, desc="上传失败,参数异常")
|
|
|
|
|
|
obj = {
|
|
|
"drug_id": drug_id if drug_id else None,
|
|
|
"dictionary_id": dictionary_id if dictionary_id else None,
|
|
|
"pic_url": img_path,
|
|
|
"is_add": 0,
|
|
|
}
|
|
|
await DrugRelationImage().create(**obj)
|
|
|
|
|
|
return respond_to(desc='上传成功')
|