增加目标追踪的模块
This commit is contained in:
@ -6,7 +6,7 @@ import torch
|
|||||||
from utils.yolov5.models.common import DetectMultiBackend
|
from utils.yolov5.models.common import DetectMultiBackend
|
||||||
from utils.yolov5.utils.torch_utils import select_device
|
from utils.yolov5.utils.torch_utils import select_device
|
||||||
from utils.yolov5.utils.dataloaders import LoadImages, LoadStreams
|
from utils.yolov5.utils.dataloaders import LoadImages, LoadStreams
|
||||||
from utils.yolov5.utils.general import check_img_size, non_max_suppression, cv2, scale_coords, xyxy2xywh, Profile
|
from utils.yolov5.utils.general import check_img_size, non_max_suppression, cv2, scale_coords, xyxy2xywh
|
||||||
from deep_sort.deep_sort import DeepSort
|
from deep_sort.deep_sort import DeepSort
|
||||||
from deep_sort.utils.draw import draw_boxes
|
from deep_sort.utils.draw import draw_boxes
|
||||||
|
|
||||||
@ -69,22 +69,17 @@ async def run_deepsort(
|
|||||||
|
|
||||||
time.sleep(2) # 等待2s,等待websocket进入
|
time.sleep(2) # 等待2s,等待websocket进入
|
||||||
|
|
||||||
dt = (Profile(device=device), Profile(device=device), Profile(device=device))
|
|
||||||
|
|
||||||
for path, im, im0s, vid_cap, s in dataset:
|
for path, im, im0s, vid_cap, s in dataset:
|
||||||
if room_manager.rooms.get(room):
|
if room_manager.rooms.get(room):
|
||||||
with dt[0]:
|
im0 = im0s[0]
|
||||||
im0 = im0s[0]
|
im = torch.from_numpy(im).to(model.device)
|
||||||
im = torch.from_numpy(im).to(model.device)
|
im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
|
||||||
im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
|
im /= 255 # 0 - 255 to 0.0 - 1.0
|
||||||
im /= 255 # 0 - 255 to 0.0 - 1.0
|
if len(im.shape) == 3:
|
||||||
if len(im.shape) == 3:
|
im = im[None] # expand for batch dim
|
||||||
im = im[None] # expand for batch dim
|
pred = model(im, augment=False, visualize=False)
|
||||||
with dt[1]:
|
# NMS
|
||||||
pred = model(im, augment=False, visualize=False)
|
pred = non_max_suppression(pred, 0.25, 0.45, None, False, max_det=1000)[0]
|
||||||
with dt[2]:
|
|
||||||
# NMS
|
|
||||||
pred = non_max_suppression(pred, 0.25, 0.45, None, False, max_det=1000)[0]
|
|
||||||
|
|
||||||
pred[:, :4] = scale_coords(im.shape[2:], pred[:, :4], im0.shape).round()
|
pred[:, :4] = scale_coords(im.shape[2:], pred[:, :4], im0.shape).round()
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ from utils.yolov5.utils.torch_utils import select_device
|
|||||||
from ultralytics.utils.plotting import Annotator, colors
|
from ultralytics.utils.plotting import Annotator, colors
|
||||||
from utils.yolov5.models.common import DetectMultiBackend
|
from utils.yolov5.models.common import DetectMultiBackend
|
||||||
from apps.business.deepsort import service as deepsort_service
|
from apps.business.deepsort import service as deepsort_service
|
||||||
from utils.yolov5.utils.general import check_img_size, Profile, non_max_suppression, cv2, scale_boxes
|
from utils.yolov5.utils.general import check_img_size, non_max_suppression, cv2, scale_boxes
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import torch
|
import torch
|
||||||
@ -97,7 +97,7 @@ async def run_detect_img(
|
|||||||
room = 'detect_' + str(detect_id)
|
room = 'detect_' + str(detect_id)
|
||||||
await room_manager.send_to_room(room, f"AiCheck: 模型训练开始,请稍等。。。\n")
|
await room_manager.send_to_room(room, f"AiCheck: 模型训练开始,请稍等。。。\n")
|
||||||
commend = ["python", '-u', yolo_path, "--weights", weights, "--source", source, "--name", name, "--project",
|
commend = ["python", '-u', yolo_path, "--weights", weights, "--source", source, "--name", name, "--project",
|
||||||
project, "--save-txt", "--conf-thres", "0.4"]
|
project, "--save-txt", "--conf-thres", "0.6"]
|
||||||
# 判断是否存在cuda版本
|
# 判断是否存在cuda版本
|
||||||
if is_gpu == 'True':
|
if is_gpu == 'True':
|
||||||
commend.append("--device=0")
|
commend.append("--device=0")
|
||||||
@ -176,25 +176,20 @@ async def run_detect_rtsp(weights_pt: str, rtsp_url: str, data: str, detect_id:
|
|||||||
|
|
||||||
model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *img_sz))
|
model.warmup(imgsz=(1 if pt or model.triton else bs, 3, *img_sz))
|
||||||
|
|
||||||
dt = (Profile(device=device), Profile(device=device), Profile(device=device))
|
time.sleep(3) # 等待3s,等待websocket进入
|
||||||
|
|
||||||
time.sleep(3) # 等待2s,等待websocket进入
|
|
||||||
|
|
||||||
for path, im, im0s, vid_cap, s in dataset:
|
for path, im, im0s, vid_cap, s in dataset:
|
||||||
if room_manager.rooms.get(room):
|
if room_manager.rooms.get(room):
|
||||||
with dt[0]:
|
im = torch.from_numpy(im).to(model.device)
|
||||||
im = torch.from_numpy(im).to(model.device)
|
im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
|
||||||
im = im.half() if model.fp16 else im.float() # uint8 to fp16/32
|
im /= 255 # 0 - 255 to 0.0 - 1.0
|
||||||
im /= 255 # 0 - 255 to 0.0 - 1.0
|
if len(im.shape) == 3:
|
||||||
if len(im.shape) == 3:
|
im = im[None] # expand for batch dim
|
||||||
im = im[None] # expand for batch dim
|
|
||||||
|
|
||||||
# Inference
|
# Inference
|
||||||
with dt[1]:
|
pred = model(im, augment=False, visualize=False)
|
||||||
pred = model(im, augment=False, visualize=False)
|
|
||||||
# NMS
|
# NMS
|
||||||
with dt[2]:
|
pred = non_max_suppression(pred, 0.25, 0.45, None, False, max_det=1000)
|
||||||
pred = non_max_suppression(pred, 0.25, 0.45, None, False, max_det=1000)
|
|
||||||
|
|
||||||
# Process predictions
|
# Process predictions
|
||||||
for i, det in enumerate(pred): # per image
|
for i, det in enumerate(pred): # per image
|
||||||
|
@ -80,8 +80,6 @@ class LoginValidation:
|
|||||||
await db.flush()
|
await db.flush()
|
||||||
elif not user.is_active:
|
elif not user.is_active:
|
||||||
self.result.msg = "此手机号已被冻结!"
|
self.result.msg = "此手机号已被冻结!"
|
||||||
elif data.platform in ["0", "1"]:
|
|
||||||
self.result.msg = "此手机号无权限!"
|
|
||||||
else:
|
else:
|
||||||
if not DEMO and count:
|
if not DEMO and count:
|
||||||
await count.delete()
|
await count.delete()
|
||||||
|
@ -7,20 +7,16 @@
|
|||||||
# @desc : 数据库 增删改查操作
|
# @desc : 数据库 增删改查操作
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from enum import Enum
|
import os
|
||||||
from typing import Any
|
from sqlalchemy import select, update
|
||||||
from redis.asyncio import Redis
|
|
||||||
from fastapi.encoders import jsonable_encoder
|
|
||||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
|
||||||
from sqlalchemy import select
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
from application.settings import SUBSCRIBE
|
from application.settings import STATIC_ROOT, REDIS_DB_ENABLE
|
||||||
from core.mongo_manage import MongoManage
|
from core.database import redis_getter
|
||||||
|
from utils.file.file_manage import FileManage
|
||||||
from . import models, schemas
|
from . import models, schemas
|
||||||
from core.crud import DalBase
|
from core.crud import DalBase
|
||||||
from core.exception import CustomException
|
from fastapi import Request
|
||||||
from utils import status
|
|
||||||
|
|
||||||
|
|
||||||
class DictTypeDal(DalBase):
|
class DictTypeDal(DalBase):
|
||||||
@ -67,323 +63,116 @@ class DictDetailsDal(DalBase):
|
|||||||
self.schema = schemas.DictDetailsSimpleOut
|
self.schema = schemas.DictDetailsSimpleOut
|
||||||
|
|
||||||
|
|
||||||
class TaskDal(MongoManage):
|
class SettingsDal(DalBase):
|
||||||
|
|
||||||
class JobOperation(Enum):
|
def __init__(self, db: AsyncSession):
|
||||||
add = "add_job"
|
super(SettingsDal, self).__init__()
|
||||||
|
self.db = db
|
||||||
|
self.model = models.VadminSystemSettings
|
||||||
|
self.schema = schemas.SettingsSimpleOut
|
||||||
|
|
||||||
def __init__(self, db: AsyncIOMotorDatabase):
|
async def get_tab_values(self, tab_id: int) -> dict:
|
||||||
super(TaskDal, self).__init__(db, "vadmin_system_task", schemas.TaskSimpleOut)
|
|
||||||
|
|
||||||
async def get_task(
|
|
||||||
self,
|
|
||||||
_id: str = None,
|
|
||||||
v_return_none: bool = False,
|
|
||||||
v_schema: Any = None,
|
|
||||||
**kwargs
|
|
||||||
) -> dict | None:
|
|
||||||
"""
|
"""
|
||||||
获取单个数据,默认使用 ID 查询,否则使用关键词查询
|
获取系统配置标签下的信息
|
||||||
|
|
||||||
包括临时字段 last_run_datetime,is_active
|
|
||||||
is_active: 只有在 scheduler_task_jobs 任务运行表中存在相同 _id 才表示任务添加成功,任务状态才为 True
|
|
||||||
last_run_datetime: 在 scheduler_task_record 中获取该任务最近一次执行完成的时间
|
|
||||||
|
|
||||||
:param _id: 数据 ID
|
|
||||||
:param v_return_none: 是否返回空 None,否则抛出异常,默认抛出异常
|
|
||||||
:param v_schema: 指定使用的序列化对象
|
|
||||||
"""
|
"""
|
||||||
if _id:
|
datas = await self.get_datas(limit=0, tab_id=tab_id, v_return_objs=True)
|
||||||
kwargs["_id"] = ("ObjectId", _id)
|
result = {}
|
||||||
|
for data in datas:
|
||||||
params = self.filter_condition(**kwargs)
|
if not data.disabled:
|
||||||
pipeline = [
|
result[data.config_key] = data.config_value
|
||||||
{
|
|
||||||
'$addFields': {
|
|
||||||
'str_id': {'$toString': '$_id'}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$lookup': {
|
|
||||||
'from': 'scheduler_task_jobs',
|
|
||||||
'localField': 'str_id',
|
|
||||||
'foreignField': '_id',
|
|
||||||
'as': 'matched_jobs'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$lookup': {
|
|
||||||
'from': 'scheduler_task_record',
|
|
||||||
'localField': 'str_id',
|
|
||||||
'foreignField': 'job_id',
|
|
||||||
'as': 'matched_records'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$addFields': {
|
|
||||||
'is_active': {
|
|
||||||
'$cond': {
|
|
||||||
'if': {'$ne': ['$matched_jobs', []]},
|
|
||||||
'then': True,
|
|
||||||
'else': False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'last_run_datetime': {
|
|
||||||
'$ifNull': [
|
|
||||||
{'$arrayElemAt': ['$matched_records.create_datetime', -1]},
|
|
||||||
None
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$business': {
|
|
||||||
'matched_records': 0,
|
|
||||||
'matched_jobs': 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$match': params
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$facet': {
|
|
||||||
'documents': [
|
|
||||||
{'$limit': 1},
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
# 执行聚合查询
|
|
||||||
cursor = self.collection.aggregate(pipeline)
|
|
||||||
result = await cursor.to_list(length=None)
|
|
||||||
data = result[0]['documents']
|
|
||||||
if not data and v_return_none:
|
|
||||||
return None
|
|
||||||
elif not data:
|
|
||||||
raise CustomException("未查找到对应数据", code=status.HTTP_404_NOT_FOUND)
|
|
||||||
data = data[0]
|
|
||||||
if data and v_schema:
|
|
||||||
return jsonable_encoder(v_schema(**data))
|
|
||||||
return data
|
|
||||||
|
|
||||||
async def get_tasks(
|
|
||||||
self,
|
|
||||||
page: int = 1,
|
|
||||||
limit: int = 10,
|
|
||||||
v_schema: Any = None,
|
|
||||||
v_order: str = None,
|
|
||||||
v_order_field: str = None,
|
|
||||||
**kwargs
|
|
||||||
) -> tuple:
|
|
||||||
"""
|
|
||||||
获取任务信息列表
|
|
||||||
|
|
||||||
添加了两个临时字段
|
|
||||||
is_active: 只有在 scheduler_task_jobs 任务运行表中存在相同 _id 才表示任务添加成功,任务状态才为 True
|
|
||||||
last_run_datetime: 在 scheduler_task_record 中获取该任务最近一次执行完成的时间
|
|
||||||
"""
|
|
||||||
v_order_field = v_order_field if v_order_field else 'create_datetime'
|
|
||||||
v_order = -1 if v_order in self.ORDER_FIELD else 1
|
|
||||||
params = self.filter_condition(**kwargs)
|
|
||||||
pipeline = [
|
|
||||||
{
|
|
||||||
'$addFields': {
|
|
||||||
'str_id': {'$toString': '$_id'}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$lookup': {
|
|
||||||
'from': 'scheduler_task_jobs',
|
|
||||||
'localField': 'str_id',
|
|
||||||
'foreignField': '_id',
|
|
||||||
'as': 'matched_jobs'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$lookup': {
|
|
||||||
'from': 'scheduler_task_record',
|
|
||||||
'localField': 'str_id',
|
|
||||||
'foreignField': 'job_id',
|
|
||||||
'as': 'matched_records'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$addFields': {
|
|
||||||
'is_active': {
|
|
||||||
'$cond': {
|
|
||||||
'if': {'$ne': ['$matched_jobs', []]},
|
|
||||||
'then': True,
|
|
||||||
'else': False
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'last_run_datetime': {
|
|
||||||
'$ifNull': [
|
|
||||||
{'$arrayElemAt': ['$matched_records.create_datetime', -1]},
|
|
||||||
None
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$business': {
|
|
||||||
'matched_records': 0,
|
|
||||||
'matched_jobs': 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$match': params
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'$facet': {
|
|
||||||
'documents': [
|
|
||||||
{'$sort': {v_order_field: v_order}},
|
|
||||||
{'$limit': limit},
|
|
||||||
{'$skip': (page - 1) * limit}
|
|
||||||
],
|
|
||||||
'count': [{'$count': 'total'}]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
# 执行聚合查询
|
|
||||||
cursor = self.collection.aggregate(pipeline)
|
|
||||||
result = await cursor.to_list(length=None)
|
|
||||||
datas = result[0]['documents']
|
|
||||||
count = result[0]['count'][0]['total'] if result[0]['count'] else 0
|
|
||||||
if count == 0:
|
|
||||||
return [], 0
|
|
||||||
elif v_schema:
|
|
||||||
datas = [jsonable_encoder(v_schema(**data)) for data in datas]
|
|
||||||
elif self.schema:
|
|
||||||
datas = [jsonable_encoder(self.schema(**data)) for data in datas]
|
|
||||||
return datas, count
|
|
||||||
|
|
||||||
async def add_task(self, rd: Redis, data: dict) -> int:
|
|
||||||
"""
|
|
||||||
添加任务到消息队列
|
|
||||||
|
|
||||||
使用消息无保留策略:无保留是指当发送者向某个频道发送消息时,如果没有订阅该频道的调用方,就直接将该消息丢弃。
|
|
||||||
|
|
||||||
:param rd: redis 对象
|
|
||||||
:param data: 行数据字典
|
|
||||||
:return: 接收到消息的订阅者数量。
|
|
||||||
"""
|
|
||||||
exec_strategy = data.get("exec_strategy")
|
|
||||||
job_params = {
|
|
||||||
"name": data.get("_id"),
|
|
||||||
"job_class": data.get("job_class"),
|
|
||||||
"expression": data.get("expression")
|
|
||||||
}
|
|
||||||
if exec_strategy == "interval" or exec_strategy == "cron":
|
|
||||||
job_params["start_date"] = data.get("start_date")
|
|
||||||
job_params["end_date"] = data.get("end_date")
|
|
||||||
message = {
|
|
||||||
"operation": self.JobOperation.add.value,
|
|
||||||
"task": {
|
|
||||||
"exec_strategy": data.get("exec_strategy"),
|
|
||||||
"job_params": job_params
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return await rd.publish(SUBSCRIBE, json.dumps(message).encode('utf-8'))
|
|
||||||
|
|
||||||
async def create_task(self, rd: Redis, data: schemas.Task) -> dict:
|
|
||||||
"""
|
|
||||||
创建任务
|
|
||||||
"""
|
|
||||||
data_dict = data.model_dump()
|
|
||||||
is_active = data_dict.pop('is_active')
|
|
||||||
insert_result = await super().create_data(data_dict)
|
|
||||||
obj = await self.get_task(insert_result.inserted_id, v_schema=schemas.TaskSimpleOut)
|
|
||||||
|
|
||||||
# 如果分组不存在则新增分组
|
|
||||||
group = await TaskGroupDal(self.db).get_data(value=data.group, v_return_none=True)
|
|
||||||
if not group:
|
|
||||||
await TaskGroupDal(self.db).create_data({"value": data.group})
|
|
||||||
|
|
||||||
result = {
|
|
||||||
"subscribe_number": 0,
|
|
||||||
"is_active": is_active
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_active:
|
|
||||||
# 创建任务成功后, 如果任务状态为 True,则向消息队列中发送任务
|
|
||||||
result['subscribe_number'] = await self.add_task(rd, obj)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
async def put_task(self, rd: Redis, _id: str, data: schemas.Task) -> dict:
|
async def update_datas(self, datas: dict, request: Request) -> None:
|
||||||
"""
|
"""
|
||||||
更新任务
|
更新系统配置信息
|
||||||
|
|
||||||
|
更新ico图标步骤:先将文件上传到本地,然后点击提交后,获取到文件地址,将上传的新文件覆盖原有文件
|
||||||
|
原因:ico图标的路径是在前端的index.html中固定的,所以目前只能改变图片,不改变路径
|
||||||
"""
|
"""
|
||||||
data_dict = data.model_dump()
|
for key, value in datas.items():
|
||||||
is_active = data_dict.pop('is_active')
|
if key == "web_ico":
|
||||||
await super(TaskDal, self).put_data(_id, data)
|
continue
|
||||||
obj: dict = await self.get_task(_id, v_schema=schemas.TaskSimpleOut)
|
elif key == "web_ico_local_path":
|
||||||
|
if not value:
|
||||||
|
continue
|
||||||
|
ico = await self.get_data(config_key="web_ico", tab_id=1)
|
||||||
|
web_ico = datas.get("web_ico")
|
||||||
|
if ico.config_value == web_ico:
|
||||||
|
continue
|
||||||
|
# 将上传的ico路径替换到static/system/favicon.ico文件
|
||||||
|
await FileManage.async_copy_file(value, os.path.join(STATIC_ROOT, "system/favicon.ico"))
|
||||||
|
sql = update(self.model).where(self.model.config_key == "web_ico").values(config_value=web_ico)
|
||||||
|
await self.db.execute(sql)
|
||||||
|
else:
|
||||||
|
sql = update(self.model).where(self.model.config_key == str(key)).values(config_value=value)
|
||||||
|
await self.db.execute(sql)
|
||||||
|
if "wx_server_app_id" in datas and REDIS_DB_ENABLE:
|
||||||
|
rd = redis_getter(request)
|
||||||
|
await rd.client().set("wx_server", json.dumps(datas))
|
||||||
|
elif "sms_access_key" in datas and REDIS_DB_ENABLE:
|
||||||
|
rd = redis_getter(request)
|
||||||
|
await rd.client().set('aliyun_sms', json.dumps(datas))
|
||||||
|
|
||||||
# 如果分组不存在则新增分组
|
async def get_base_config(self) -> dict:
|
||||||
group = await TaskGroupDal(self.db).get_data(value=data.group, v_return_none=True)
|
"""
|
||||||
if not group:
|
获取系统基本信息
|
||||||
await TaskGroupDal(self.db).create_data({"value": data.group})
|
"""
|
||||||
|
ignore_configs = ["wx_server_app_id", "wx_server_app_secret"]
|
||||||
try:
|
datas = await self.get_datas(limit=0, tab_id=("in", ["1", "9"]), disabled=False, v_return_objs=True)
|
||||||
# 删除正在运行中的 Job
|
result = {}
|
||||||
await SchedulerTaskJobsDal(self.db).delete_data(_id)
|
for config in datas:
|
||||||
except CustomException as e:
|
if config.config_key not in ignore_configs:
|
||||||
pass
|
result[config.config_key] = config.config_value
|
||||||
|
|
||||||
result = {
|
|
||||||
"subscribe_number": 0,
|
|
||||||
"is_active": is_active
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_active:
|
|
||||||
# 更新任务成功后, 如果任务状态为 True,则向消息队列中发送任务
|
|
||||||
result['subscribe_number'] = await self.add_task(rd, obj)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
async def delete_task(self, _id: str) -> bool:
|
|
||||||
"""
|
|
||||||
删除任务
|
|
||||||
"""
|
|
||||||
result = await super(TaskDal, self).delete_data(_id)
|
|
||||||
|
|
||||||
try:
|
class SettingsTabDal(DalBase):
|
||||||
# 删除正在运行中的 Job
|
|
||||||
await SchedulerTaskJobsDal(self.db).delete_data(_id)
|
|
||||||
except CustomException as e:
|
|
||||||
pass
|
|
||||||
return result
|
|
||||||
|
|
||||||
async def run_once_task(self, rd: Redis, _id: str) -> int:
|
def __init__(self, db: AsyncSession):
|
||||||
|
super(SettingsTabDal, self).__init__(db, models.VadminSystemSettingsTab, schemas.SettingsTabSimpleOut)
|
||||||
|
|
||||||
|
async def get_classify_tab_values(self, classify: list[str], hidden: bool | None = False) -> dict:
|
||||||
"""
|
"""
|
||||||
执行一次任务
|
获取系统配置分类下的标签信息
|
||||||
"""
|
"""
|
||||||
obj: dict = await self.get_data(_id, v_schema=schemas.TaskSimpleOut)
|
model = models.VadminSystemSettingsTab
|
||||||
message = {
|
options = [joinedload(model.settings)]
|
||||||
"operation": self.JobOperation.add.value,
|
datas = await self.get_datas(
|
||||||
"task": {
|
limit=0,
|
||||||
"exec_strategy": "once",
|
v_options=options,
|
||||||
"job_params": {
|
classify=("in", classify),
|
||||||
"name": obj.get("_id"),
|
disabled=False,
|
||||||
"job_class": obj.get("job_class")
|
v_return_objs=True,
|
||||||
}
|
hidden=hidden
|
||||||
|
)
|
||||||
|
return self.__generate_values(datas)
|
||||||
|
|
||||||
|
async def get_tab_name_values(self, tab_names: list[str], hidden: bool | None = False) -> dict:
|
||||||
|
"""
|
||||||
|
获取系统配置标签下的标签信息
|
||||||
|
"""
|
||||||
|
model = models.VadminSystemSettingsTab
|
||||||
|
options = [joinedload(model.settings)]
|
||||||
|
datas = await self.get_datas(
|
||||||
|
limit=0,
|
||||||
|
v_options=options,
|
||||||
|
tab_name=("in", tab_names),
|
||||||
|
disabled=False,
|
||||||
|
v_return_objs=True,
|
||||||
|
hidden=hidden
|
||||||
|
)
|
||||||
|
return self.__generate_values(datas)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def __generate_values(cls, datas: list[models.VadminSystemSettingsTab]) -> dict:
|
||||||
|
"""
|
||||||
|
生成字典值
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
tab.tab_name: {
|
||||||
|
item.config_key: item.config_value
|
||||||
|
for item in tab.settings
|
||||||
|
if not item.disabled
|
||||||
}
|
}
|
||||||
|
for tab in datas
|
||||||
}
|
}
|
||||||
return await rd.publish(SUBSCRIBE, json.dumps(message).encode('utf-8'))
|
|
||||||
|
|
||||||
|
|
||||||
class TaskGroupDal(MongoManage):
|
|
||||||
|
|
||||||
def __init__(self, db: AsyncIOMotorDatabase):
|
|
||||||
super(TaskGroupDal, self).__init__(db, "vadmin_system_task_group")
|
|
||||||
|
|
||||||
|
|
||||||
class TaskRecordDal(MongoManage):
|
|
||||||
|
|
||||||
def __init__(self, db: AsyncIOMotorDatabase):
|
|
||||||
super(TaskRecordDal, self).__init__(db, "scheduler_task_record")
|
|
||||||
|
|
||||||
|
|
||||||
class SchedulerTaskJobsDal(MongoManage):
|
|
||||||
|
|
||||||
def __init__(self, db: AsyncIOMotorDatabase):
|
|
||||||
super(SchedulerTaskJobsDal, self).__init__(db, "scheduler_task_jobs", is_object_id=False)
|
|
||||||
|
@ -1 +1,2 @@
|
|||||||
from .dict import VadminDictType, VadminDictDetails
|
from .dict import VadminDictType, VadminDictDetails
|
||||||
|
from .settings import VadminSystemSettings, VadminSystemSettingsTab
|
||||||
|
42
apps/vadmin/system/models/settings.py
Normal file
42
apps/vadmin/system/models/settings.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @version : 1.0
|
||||||
|
# @Create Time : 2022/7/7 13:41
|
||||||
|
# @File : settings.py
|
||||||
|
# @IDE : PyCharm
|
||||||
|
# @desc : 系统字典模型
|
||||||
|
from sqlalchemy.orm import relationship, Mapped, mapped_column
|
||||||
|
from db.db_base import BaseModel
|
||||||
|
from sqlalchemy import String, Integer, ForeignKey, Boolean, Text
|
||||||
|
|
||||||
|
|
||||||
|
class VadminSystemSettingsTab(BaseModel):
|
||||||
|
__tablename__ = "vadmin_system_settings_tab"
|
||||||
|
__table_args__ = ({'comment': '系统配置分类表'})
|
||||||
|
|
||||||
|
title: Mapped[str] = mapped_column(String(255), comment="标题")
|
||||||
|
classify: Mapped[str] = mapped_column(String(255), index=True, nullable=False, comment="分类键")
|
||||||
|
tab_label: Mapped[str] = mapped_column(String(255), comment="tab标题")
|
||||||
|
tab_name: Mapped[str] = mapped_column(String(255), index=True, nullable=False, unique=True, comment="tab标识符")
|
||||||
|
hidden: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否隐藏")
|
||||||
|
disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
|
||||||
|
|
||||||
|
settings: Mapped[list["VadminSystemSettings"]] = relationship(back_populates="tab")
|
||||||
|
|
||||||
|
|
||||||
|
class VadminSystemSettings(BaseModel):
|
||||||
|
__tablename__ = "vadmin_system_settings"
|
||||||
|
__table_args__ = ({'comment': '系统配置表'})
|
||||||
|
|
||||||
|
config_label: Mapped[str] = mapped_column(String(255), comment="配置表标签")
|
||||||
|
config_key: Mapped[str] = mapped_column(String(255), index=True, nullable=False, unique=True, comment="配置表键")
|
||||||
|
config_value: Mapped[str | None] = mapped_column(Text, comment="配置表内容")
|
||||||
|
remark: Mapped[str | None] = mapped_column(String(255), comment="备注信息")
|
||||||
|
disabled: Mapped[bool] = mapped_column(Boolean, default=False, comment="是否禁用")
|
||||||
|
|
||||||
|
tab_id: Mapped[int] = mapped_column(
|
||||||
|
Integer,
|
||||||
|
ForeignKey("vadmin_system_settings_tab.id", ondelete='CASCADE'),
|
||||||
|
comment="关联tab标签"
|
||||||
|
)
|
||||||
|
tab: Mapped[VadminSystemSettingsTab] = relationship(foreign_keys=tab_id, back_populates="settings")
|
@ -1,3 +1,2 @@
|
|||||||
from .dict_type import DictTypeParams
|
from .dict_type import DictTypeParams
|
||||||
from .dict_detail import DictDetailParams
|
from .dict_detail import DictDetailParams
|
||||||
from .task import TaskParams
|
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @version : 1.0
|
|
||||||
# @Create Time : 2023/6/25 14:50
|
|
||||||
# @File : task.py
|
|
||||||
# @IDE : PyCharm
|
|
||||||
# @desc : 简要说明
|
|
||||||
from fastapi import Depends
|
|
||||||
from core.dependencies import Paging, QueryParams
|
|
||||||
|
|
||||||
|
|
||||||
class TaskParams(QueryParams):
|
|
||||||
"""
|
|
||||||
列表分页
|
|
||||||
"""
|
|
||||||
def __init__(self, name: str = None, _id: str = None, group: str = None, params: Paging = Depends()):
|
|
||||||
super().__init__(params)
|
|
||||||
self.name = ("like", name)
|
|
||||||
self.group = group
|
|
||||||
self._id = ("ObjectId", _id)
|
|
||||||
self.v_order = "desc"
|
|
||||||
|
|
||||||
|
|
||||||
class TaskRecordParams(QueryParams):
|
|
||||||
"""
|
|
||||||
列表分页
|
|
||||||
"""
|
|
||||||
def __init__(self, job_id: str = None, name: str = None, params: Paging = Depends()):
|
|
||||||
super().__init__(params)
|
|
||||||
self.job_id = ("like", job_id)
|
|
||||||
self.name = ("like", name)
|
|
||||||
self.v_order = "desc"
|
|
@ -1,2 +1,3 @@
|
|||||||
from .dict import DictType, DictDetails, DictTypeSimpleOut, DictDetailsSimpleOut, DictTypeOptionsOut
|
from .dict import DictType, DictDetails, DictTypeSimpleOut, DictDetailsSimpleOut, DictTypeOptionsOut
|
||||||
from .task import Task, TaskSimpleOut
|
from .settings_tab import SettingsTab, SettingsTabSimpleOut
|
||||||
|
from .settings import Settings, SettingsSimpleOut
|
||||||
|
29
apps/vadmin/system/schemas/settings.py
Normal file
29
apps/vadmin/system/schemas/settings.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @version : 1.0
|
||||||
|
# @Create Time : 2021/10/18 22:19
|
||||||
|
# @File : settings.py
|
||||||
|
# @IDE : PyCharm
|
||||||
|
# @desc : pydantic 模型,用于数据库序列化操作
|
||||||
|
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from core.data_types import DatetimeStr
|
||||||
|
|
||||||
|
|
||||||
|
class Settings(BaseModel):
|
||||||
|
config_label: str | None = None
|
||||||
|
config_key: str
|
||||||
|
config_value: str | None = None
|
||||||
|
remark: str | None = None
|
||||||
|
disabled: bool | None = None
|
||||||
|
tab_id: int
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsSimpleOut(Settings):
|
||||||
|
model_config = ConfigDict(from_attributes=True)
|
||||||
|
|
||||||
|
id: int
|
||||||
|
create_datetime: DatetimeStr
|
||||||
|
update_datetime: DatetimeStr
|
||||||
|
|
28
apps/vadmin/system/schemas/settings_tab.py
Normal file
28
apps/vadmin/system/schemas/settings_tab.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# @version : 1.0
|
||||||
|
# @Create Time : 2021/10/18 22:19
|
||||||
|
# @File : settings_tab.py
|
||||||
|
# @IDE : PyCharm
|
||||||
|
# @desc : pydantic 模型,用于数据库序列化操作
|
||||||
|
|
||||||
|
|
||||||
|
from pydantic import BaseModel, ConfigDict
|
||||||
|
from core.data_types import DatetimeStr
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsTab(BaseModel):
|
||||||
|
title: str
|
||||||
|
classify: str
|
||||||
|
tab_label: str
|
||||||
|
tab_name: str
|
||||||
|
hidden: bool
|
||||||
|
|
||||||
|
|
||||||
|
class SettingsTabSimpleOut(SettingsTab):
|
||||||
|
model_config = ConfigDict(from_attributes=True)
|
||||||
|
|
||||||
|
id: int
|
||||||
|
create_datetime: DatetimeStr
|
||||||
|
update_datetime: DatetimeStr
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# @version : 1.0
|
|
||||||
# @Create Time : 2023/6/25 15:08
|
|
||||||
# @File : task.py
|
|
||||||
# @IDE : PyCharm
|
|
||||||
# @desc : 简要说明
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, ConfigDict
|
|
||||||
from core.data_types import DatetimeStr, ObjectIdStr
|
|
||||||
|
|
||||||
|
|
||||||
class Task(BaseModel):
|
|
||||||
name: str
|
|
||||||
group: str | None = None
|
|
||||||
job_class: str
|
|
||||||
exec_strategy: str
|
|
||||||
expression: str
|
|
||||||
is_active: bool | None = True # 临时字段,不在表中创建
|
|
||||||
remark: str | None = None
|
|
||||||
start_date: DatetimeStr | None = None
|
|
||||||
end_date: DatetimeStr | None = None
|
|
||||||
|
|
||||||
|
|
||||||
class TaskSimpleOut(Task):
|
|
||||||
model_config = ConfigDict(from_attributes=True)
|
|
||||||
|
|
||||||
id: ObjectIdStr = Field(..., alias='_id')
|
|
||||||
create_datetime: DatetimeStr
|
|
||||||
update_datetime: DatetimeStr
|
|
||||||
last_run_datetime: DatetimeStr | None = None # 临时字段,不在表中创建
|
|
||||||
|
|
@ -5,19 +5,16 @@
|
|||||||
# @IDE : PyCharm
|
# @IDE : PyCharm
|
||||||
# @desc : 主要接口文件
|
# @desc : 主要接口文件
|
||||||
|
|
||||||
from redis.asyncio import Redis
|
from fastapi import APIRouter, Depends, Body, Request
|
||||||
from fastapi import APIRouter, Depends, Body
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
from motor.motor_asyncio import AsyncIOMotorDatabase
|
from core.database import db_getter
|
||||||
from core.database import redis_getter, mongo_getter
|
from utils.response import SuccessResponse
|
||||||
from utils.response import SuccessResponse, ErrorResponse
|
|
||||||
from utils.sms.code import CodeSMS
|
|
||||||
from . import schemas, crud
|
from . import schemas, crud
|
||||||
from core.dependencies import IdList
|
from core.dependencies import IdList
|
||||||
from apps.vadmin.auth.utils.current import AllUserAuth, OpenAuth
|
from apps.vadmin.auth.utils.current import AllUserAuth, FullAdminAuth, OpenAuth
|
||||||
from apps.vadmin.auth.utils.validation.auth import Auth
|
from apps.vadmin.auth.utils.validation.auth import Auth
|
||||||
from .params import DictTypeParams, DictDetailParams, TaskParams
|
from .params import DictTypeParams, DictDetailParams
|
||||||
from apps.vadmin.auth import crud as vadmin_auth_crud
|
|
||||||
from .params.task import TaskRecordParams
|
|
||||||
|
|
||||||
app = APIRouter()
|
app = APIRouter()
|
||||||
|
|
||||||
@ -99,96 +96,39 @@ async def get_dict_detail(data_id: int, auth: Auth = Depends(AllUserAuth())):
|
|||||||
|
|
||||||
|
|
||||||
###########################################################
|
###########################################################
|
||||||
# 短信服务管理
|
# 系统配置管理
|
||||||
###########################################################
|
###########################################################
|
||||||
@app.post("/sms/send", summary="发送短信验证码(阿里云服务)")
|
@app.post("/settings/tabs", summary="获取系统配置标签列表")
|
||||||
async def sms_send(telephone: str, rd: Redis = Depends(redis_getter), auth: Auth = Depends(OpenAuth())):
|
async def get_settings_tabs(classifys: list[str] = Body(...), auth: Auth = Depends(FullAdminAuth())):
|
||||||
user = await vadmin_auth_crud.UserDal(auth.db).get_data(telephone=telephone, v_return_none=True)
|
return SuccessResponse(await crud.SettingsTabDal(auth.db).get_datas(limit=0, classify=("in", classifys)))
|
||||||
if not user:
|
|
||||||
return ErrorResponse("手机号不存在!")
|
|
||||||
sms = CodeSMS(telephone, rd)
|
|
||||||
return SuccessResponse(await sms.main_async())
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################
|
@app.get("/settings/tabs/values", summary="获取系统配置标签下的信息")
|
||||||
# 定时任务管理
|
async def get_settings_tabs_values(tab_id: int, auth: Auth = Depends(FullAdminAuth())):
|
||||||
###########################################################
|
return SuccessResponse(await crud.SettingsDal(auth.db).get_tab_values(tab_id=tab_id))
|
||||||
@app.get("/tasks", summary="获取定时任务列表")
|
|
||||||
async def get_tasks(
|
|
||||||
p: TaskParams = Depends(),
|
@app.put("/settings/tabs/values", summary="更新系统配置信息")
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
async def put_settings_tabs_values(
|
||||||
auth: Auth = Depends(AllUserAuth())
|
request: Request,
|
||||||
|
datas: dict = Body(...),
|
||||||
|
auth: Auth = Depends(FullAdminAuth())
|
||||||
):
|
):
|
||||||
datas, count = await crud.TaskDal(db).get_tasks(**p.dict())
|
return SuccessResponse(await crud.SettingsDal(auth.db).update_datas(datas, request))
|
||||||
return SuccessResponse(datas, count=count)
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/tasks", summary="添加定时任务")
|
@app.get("/settings/base/config", summary="获取系统基础配置", description="每次进入系统中时使用")
|
||||||
async def post_tasks(
|
async def get_setting_base_config(db: AsyncSession = Depends(db_getter)):
|
||||||
data: schemas.Task,
|
return SuccessResponse(await crud.SettingsDal(db).get_base_config())
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
rd: Redis = Depends(redis_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
return SuccessResponse(await crud.TaskDal(db).create_task(rd, data))
|
|
||||||
|
|
||||||
|
|
||||||
@app.put("/tasks", summary="更新定时任务")
|
@app.get("/settings/privacy", summary="获取隐私协议")
|
||||||
async def put_tasks(
|
async def get_settings_privacy(auth: Auth = Depends(OpenAuth())):
|
||||||
_id: str,
|
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_privacy")).config_value)
|
||||||
data: schemas.Task,
|
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
rd: Redis = Depends(redis_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
return SuccessResponse(await crud.TaskDal(db).put_task(rd, _id, data))
|
|
||||||
|
|
||||||
|
|
||||||
@app.delete("/tasks", summary="删除单个定时任务")
|
@app.get("/settings/agreement", summary="获取用户协议")
|
||||||
async def delete_task(
|
async def get_settings_agreement(auth: Auth = Depends(OpenAuth())):
|
||||||
_id: str,
|
return SuccessResponse((await crud.SettingsDal(auth.db).get_data(config_key="web_agreement")).config_value)
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
return SuccessResponse(await crud.TaskDal(db).delete_task(_id))
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/task", summary="获取定时任务详情")
|
|
||||||
async def get_task(
|
|
||||||
_id: str,
|
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
return SuccessResponse(await crud.TaskDal(db).get_task(_id, v_schema=schemas.TaskSimpleOut))
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/task", summary="执行一次定时任务")
|
|
||||||
async def run_once_task(
|
|
||||||
_id: str,
|
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
rd: Redis = Depends(redis_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
return SuccessResponse(await crud.TaskDal(db).run_once_task(rd, _id))
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################
|
|
||||||
# 定时任务分组管理
|
|
||||||
###########################################################
|
|
||||||
@app.get("/task/group/options", summary="获取定时任务分组选择项列表")
|
|
||||||
async def get_task_group_options(db: AsyncIOMotorDatabase = Depends(mongo_getter), auth: Auth = Depends(AllUserAuth())):
|
|
||||||
return SuccessResponse(await crud.TaskGroupDal(db).get_datas(limit=0))
|
|
||||||
|
|
||||||
|
|
||||||
###########################################################
|
|
||||||
# 定时任务调度日志
|
|
||||||
###########################################################
|
|
||||||
@app.get("/task/records", summary="获取定时任务调度日志列表")
|
|
||||||
async def get_task_records(
|
|
||||||
p: TaskRecordParams = Depends(),
|
|
||||||
db: AsyncIOMotorDatabase = Depends(mongo_getter),
|
|
||||||
auth: Auth = Depends(AllUserAuth())
|
|
||||||
):
|
|
||||||
count = await crud.TaskRecordDal(db).get_count(**p.to_count())
|
|
||||||
datas = await crud.TaskRecordDal(db).get_datas(**p.dict())
|
|
||||||
return SuccessResponse(datas, count=count)
|
|
||||||
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
Reference in New Issue
Block a user