from apiflask import APIBlueprint from iti.applications.extensions import db, sys_log from iti.applications.common.utils import success, page_schema, page from iti.applications.models import ( IotDevice, IotEndpoint, IotNode, IotNodeSchema, ) from .schemas.node import ( NodeQuery, NodeAddRequest, NodeUpdateRequest, ) from iti.applications.service.iot import ( iot_influxdb, ) from iti.applications.service.iot.alert import delete_node_alert_rule from iti.applications.common import ModelFilter from iti.applications.common.exceptions.biz_exp import BizException from flask_jwt_extended import jwt_required from sqlalchemy import select, delete, exists from sqlalchemy.sql.functions import func from sqlalchemy.orm import noload from iti.applications.common import permission bp = APIBlueprint("iot_node", __name__, url_prefix="/node", tag="采集节点管理") @bp.get("/list") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:list") @bp.input(NodeQuery.Schema(partial=True), location="query") @bp.output(IotNodeSchema(many=True)) def list_node(query_data: NodeQuery): """ 获取采集节点列表 """ return success(get_list(query_data)) @bp.get("/page") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:list") @bp.input(NodeQuery.Schema(partial=True), location="query") @bp.output(page_schema(IotNodeSchema(many=True))) def page_node(query_data: NodeQuery): """ 分页获取采集节点列表 """ return page(get_page(query_data)) @bp.get("/count") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:list") def count_node(): """ 统计采集节点数量 """ countData = {} nodeReady = db.session.query(func.count(IotNode.id).label('number')).filter_by(status=1).first().number nodeUnready = db.session.query(func.count(IotNode.id).label('number')).filter_by(status=0).first().number countData["ready"] = nodeReady countData["unReady"] = nodeUnready countData["total"] = nodeReady + nodeUnready return success(countData) @bp.post("/add") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:add") @bp.input(NodeAddRequest, location="json") def add_node(json_data: dict): """ 添加采集节点信息 """ node = IotNode(**json_data) endpoint = db.session.scalar( select(IotEndpoint) .filter_by(id=node.endpoint_id)) if not endpoint: raise BizException("采集端信息不存在") device = db.session.scalar( select(IotDevice) .options(noload(IotDevice.workshop)) .filter_by(id=node.device_id)) if not device: raise BizException("设备信息不存在") # 判断节点编号是否唯一 if json_data.get("node_number") is not None: if db.session.scalar( select( exists().where( IotNode.node_number == json_data.get("node_number"), IotNode.id != id ) ) ): raise BizException("同编号节点已存在") node.workshop_id = device.workshop_id node.status = 0 db.session.add(node) db.session.commit() return success() @bp.put("/") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:update") @bp.input(NodeUpdateRequest(partial=True), location="json") def update_node(id: int, json_data: dict): """ 更新采集节点信息 """ # 判断节点编号是否唯一 if json_data.get("node_number") is not None: if db.session.scalar( select( exists().where( IotNode.node_number == json_data.get("node_number"), IotNode.id != id ) ) ): raise BizException("同编号节点已存在") node = db.session.scalar( select(IotNode) .options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)) .filter_by(id=id)) if not node: raise BizException("节点信息不存在") for key, value in json_data.items(): if value is not None: setattr(node, key, value) db.session.commit() return success() @bp.delete("/") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:delete") def delete_node(id: int): """ 删除采集节点信息 """ node = db.session.scalar( select(IotNode) .options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)) .filter_by(id=id)) if not node: raise BizException("采集节点不存在") # 删除节点告警规则 delete_node_alert_rule(node) # 删除 db.session.delete(node) db.session.commit() return success() @bp.get("/monitoring/") @jwt_required() @bp.doc(security="JWT") @permission("iot:node:list") def get_node_alert_data(id: int): """ 获取监控数据 """ node = db.session.scalar( select(IotNode) .options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)) .filter_by(id=id)) if not node: raise BizException("采集节点不存在") measurement = f"ep{node.endpoint_id}_nd{node.id}" resultData = {} resultData["nodeNumber"] = node.node_number resultData["title"] = node.title resultData["dataType"] = node.data_type resultData["tagLabel"] = node.tag_label resultData["mark"] = node.mark resultData["monitoringData"] = iot_influxdb.query_table(measurement, node.tag_label) return success(resultData) def get_page(query_data: NodeQuery): """ 获取采集节点分页 """ query = select(IotNode).order_by(IotNode.created_at.desc()) if query_data.keyword: kw = ModelFilter.escape_like(query_data.keyword) query = query.filter( IotNode.node_number.like(f"%{kw}%") ) if query_data.endpoint_id: query = query.filter(IotNode.endpoint_id == query_data.endpoint_id) if query_data.device_id: query = query.filter(IotNode.device_id == query_data.device_id) elif query_data.workshop_id: query = query.filter(IotNode.workshop_id == query_data.workshop_id) if query_data.status is not None: query = query.filter(IotNode.status == query_data.status) return db.paginate(query, page=query_data.page, per_page=query_data.size) def get_list(query_data: NodeQuery): """ 获取采集节点列表 """ query = select(IotNode).options(noload(IotNode.workshop), noload(IotNode.device), noload(IotNode.endpoint)).order_by(IotNode.created_at.desc()) if query_data.keyword: kw = ModelFilter.escape_like(query_data.keyword) query = query.filter( IotNode.node_number.like(f"%{kw}%") ) if query_data.endpoint_id: query = query.filter(IotNode.endpoint_id == query_data.endpoint_id) if query_data.device_id: query = query.filter(IotNode.device_id == query_data.device_id) elif query_data.workshop_id: query = query.filter(IotNode.workshop_id == query_data.workshop_id) if query_data.status is not None: query = query.filter(IotNode.status == query_data.status) return db.session.scalars(query).all()