This commit is contained in:
sladro 2026-02-03 13:44:11 +08:00
parent 64793795da
commit 0ea6f481b4
298 changed files with 2376 additions and 49405 deletions

58
ruoyi-fastapi-backend/.gitignore vendored Normal file
View File

@ -0,0 +1,58 @@
# General
.DS_Store
.AppleDouble
.LSOverride
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
.pytest_cache/
.mypy_cache/
.ruff_cache/
# Virtual Environment
venv/
.venv/
ENV/
# Logs
*.log
# IDEs
.idea/
.vscode/
*.swp
*.swo
# Project specific (local artifacts)
server.py
visitor/visitorIds.txt
.env.dev
.env.prod
employee/
employee/face_images/
test/
visitor/
myenv/

View File

@ -0,0 +1,96 @@
from utils.haikang_util import HaikangUtil
import asyncio
import base64
# 查询门禁点列表
async def get_door_list_service(pageNo: int = 1, pageSize: int = 10):
result = await HaikangUtil.get_door_list_v2(pageNo, pageSize)
print(result)
# 查询门禁状态
async def get_door_status_service(door_index_codes):
result = await HaikangUtil.get_door_status(door_index_codes)
print(result)
# 门禁控制
async def door_do_control_service(door_index_codes, control_type):
result = await HaikangUtil.door_do_control(door_index_codes, control_type)
print(result)
# 查询门禁点事件
async def query_door_events_service(door_index_code,pageNo, pageSize, startTime, endTime):
result = await HaikangUtil.query_door_events_v2(door_index_code, pageNo=pageNo, pageSize=pageSize ,startTime=startTime, endTime=endTime)
print(result)
# 查看门禁点在线状态
async def door_online_status_service(door_index_codes):
result = await HaikangUtil.door_online_status(door_index_codes)
print(result)
# 按条件查询人脸分组, 很重要
async def get_face_group_service():
result = await HaikangUtil.get_face_group()
print(result)
# 人脸分组1vN搜索
async def face_group_1vN_search_service(image_path):
with open(image_path, 'rb') as f:
image_data = f.read()
encoded_image = base64.b64encode(image_data).decode('utf-8')
result = await HaikangUtil.face_group_1vN_search(
facePicBinaryData=encoded_image,
pageNo=1,
pageSize=10,
searchNum=99,
minSimilarity=50,
faceGroupIndexCodes=['5dc82633-a4cb-4107-b55e-f21bf952f9']
)
print(result)
# 人脸评分
async def face_picture_check(image_path):
with open(image_path, 'rb') as f:
image_data = f.read()
encoded_image = base64.b64encode(image_data).decode('utf-8')
result = await HaikangUtil.face_picture_check(
facePicBinaryData=encoded_image
)
print(result)
# 查询访客预约记录
async def query_visitor_record():
result = await HaikangUtil.query_visitor_record()
print(result)
if __name__ == '__main__':
# asyncio.run(get_door_list_service())
# print("*"*100)
# asyncio.run(get_door_status_service(['D01']))
# print("*"*100)
# asyncio.run(door_do_control_service(['D01'], 1))
# asyncio.run(query_door_events_service('D01',1,10,1640995200,1640995200))
# asyncio.run(get_face_group_service())
# image_path = "75c03e462769c81b6a8513d90ff2a27d.jpg"
# asyncio.run(face_group_1vN_search_service(image_path))
# asyncio.run(face_picture_check(image_path))
# asyncio.run(query_visitor_record())
asyncio.run(door_online_status_service(["xxxxxxxx"]))

View File

@ -0,0 +1,536 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from http.server import HTTPServer, BaseHTTPRequestHandler
import json
import urllib.parse
import logging
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class CustomHTTPRequestHandler(BaseHTTPRequestHandler):
"""自定义HTTP请求处理器"""
def do_GET(self):
"""处理GET请求"""
# 解析URL和查询参数
parsed_path = urllib.parse.urlparse(self.path)
query_params = urllib.parse.parse_qs(parsed_path.query)
logger.info(f"GET 请求: {self.path}")
# 根据路径返回不同的响应
if parsed_path.path == "/":
self._send_response(200, "text/html", self._get_home_page())
elif parsed_path.path == "/api/user":
self._handle_user_api(query_params)
elif parsed_path.path == "/api/status":
self._send_json_response(200, {"status": "ok", "message": "服务运行正常"})
elif parsed_path.path == "/api/time":
import datetime
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self._send_json_response(200, {"time": current_time})
else:
self._send_json_response(404, {"error": "页面未找到"})
def do_POST(self):
"""处理POST请求"""
content_length = int(self.headers.get("Content-Length", 0))
post_data = self.rfile.read(content_length)
logger.info(f"POST 请求: {self.path}")
try:
# 尝试解析JSON数据
if content_length == 0:
logger.info("POST 请求数据为空")
elif self.headers.get("Content-Type") == "application/json":
data = json.loads(post_data.decode("utf-8"))
logger.info(f"接收到JSON数据: {data}")
else:
# 解析表单数据
data = urllib.parse.parse_qs(post_data.decode("utf-8"))
logger.info(f"接收到表单数据: {data}")
# print("x"*100)
# 根据路径处理不同的POST请求
# if self.path == '/api/login':
# self._handle_login(data)
# elif self.path == '/api/echo':
# self._send_json_response(200, {'echo': data, 'message': '数据已接收'})
# else:
# self._send_json_response(404, {'error': '接口未找到'})
if self.path == "/api/resource/v2/door/search":
self._send_json_response(
200,
{
"code": "0",
"msg": "SUCCESS",
"data": {
"total": 3,
"pageNo": 1,
"pageSize": 1,
"list": [
{
"indexCode": "df8w8cr800283c24c",
"resourceType": "door",
"name": "资源 1",
"doorNo": "123",
"channelNo": "1",
"parentIndexCode": "80d9099q9e991231",
"controlOneId": "11111111",
"controlTwoId": "2222222222",
"readerInId": "ac789y2c0019c",
"readerOutId": "arcew78c710",
"doorSerial": 1,
"treatyType": "hiksdk_net",
"regionIndexCode": "d8a5476e-25c0-4aa2-b7e3-db3788ba1f77",
"regionPath": "@root000000@",
"createTime": "2018-11-28T16:47:27:358+08:00",
"updateTime": "2018-11-28T16:48:34:011+08:00",
"description": "Test",
"channelType": "door",
"regionName": "acs_setUp_42054",
"regionPathName": "@root000000@9ca1eef0-4579-4e7e-a601-caf486442d54@",
"installLocation": "位置 1",
}
],
},
},
)
elif self.path == "/api/v1/door/states":
self._send_json_response(
200,
{
"code": "0",
"msg": "success",
"data": {
"authDoorList": [
{
"doorIndexCode": "e8e3ef5c149243abb4341124ab38fcfc",
"doorState": 0,
}
],
"noAuthDoorIndexCodeList": [
"e8e3ef5c149243abb4341124ab38fcfc"
],
},
},
)
elif self.path == "/api/acs/v1/door/doControl":
self._send_json_response(
200,
{
"code": "0",
"msg": "success",
"data": [
{
"doorIndexCode": "2c95c028a809448f962a969e3ab34f",
"controlResultCode": 0, # 0表示反控成功, 其他表示失败
"controlResultDesc": "success",
}
],
},
)
elif self.path == "/api/acs/v2/door/events":
self._send_json_response(
200,
{
"code": "0",
"msg": "success",
"data": {
"total": 1,
"totalPage": 1,
"pageNo": 1,
"pageSize": 100,
"list": [
{
"eventId": "207dd3b1-37a7-4d6c-8e4d-c8bfd343051b",
"eventName": "acs.acs.eventType.successCard",
"eventTime": "2019-11-16T15:44:33+08:00",
"personId": "216e2ba145824269a1cbb423cdc85cb1",
"cardNo": "3891192334",
"personName": "sdk 人员 1zzzcb",
"orgIndexCode": "root000000",
"orgName": "默认组织",
"doorName": "10.40.239.69new_test2_门_1",
"doorIndexCode": "f0b50050d3434f15b4e34f885d5dacfe",
"doorRegionIndexCode": "fd2df06b-1afb-4c9b-b058-5740c2c00076",
"picUri": "no-pcnvr",
"svrIndexCode": "/pic?=d62i7f6e*6a7i125-c838b9--a8c67dea96e65icb1*=sd*=5dpi*=1dpi*m2i1t=4ed35444bb4s=-39",
"eventType": 198914,
"inAndOutType": 1,
"readerDevIndexCode": "378e563bf3e84d5ba6ef5742bbaa8933",
"readerDevName": "读卡器_1",
"devIndexCode": "dcff422aad9c4d60a47b8b2fe2757b71",
"devName": "10.40.239.69new_test2",
"identityCardUri": "/pic?=d62i7f6e*6a7i125-c838b9--a8c67dea96e65icb1*=sd*=5dpi*=1dpi*m2i1t=4ed35444bb4s=-39z422d3",
"receiveTime": "2019-11-16T15:45:13.525+08:00",
"jobNo": "23333",
"studentId": "201900001",
"certNo": "320826199012110005",
}
],
},
},
)
elif self.path == "/api/frs/v1/face/group":
self._send_json_response(
200,
{
"code": "0",
"msg": "Success",
"data": [
{
"indexCode": "5dc82633-a4cb-4107-b55e-f21bf952f9",
"name": "仓库值守人员",
"description": "仓库值守人员是指守着仓库的人",
}
],
},
)
elif self.path == "/api/frs/v1/application/oneToMany":
self._send_json_response(
200,
{
"code": "0",
"msg": "Success.",
"data": {
"total": 500,
"pageNo": 1,
"pageSize": 10,
"list": [
{
"similarity": 80,
"indexCode": "7cc0adb2-a3c3-48fd-b432-718103e85c28",
"faceInfo": {
"name": "张三",
"sex": "1",
"certificateType": "111",
"certificateNum": "420204199605121656",
},
"facePic": {
"faceUrl": "http://10.166.165.121:8080/frs/facepicturetemp/test.jpg"
},
}
],
},
},
)
elif self.path == "/api/frs/v1/face/picture/check":
self._send_json_response(
200,
{
"code": "0",
"msg": "Success",
"data": {
"checkResult": True,
"faceScore": 90,
"facePicAnalysisResult": {
"id": 5566,
"age": 16,
"ageRange": 1,
"ageGroup": "TEENAGER",
"": "male",
"glasses": "NO",
"smile": "NO",
"facePose": {
"pitch": 45,
"yaw": 25,
"roll": 10,
"clearityScore": 0.5,
"colorConfidence": 0.5,
"eyeDistance": 300,
"grayMean": 120,
"visibleScore": 0.5,
},
"targetModelData": "DD",
"faceRect": {
"height": 12.1,
"width": 16,
"x": 15,
"y": 3,
},
"recommendFaceRect": {
"height": 4,
"width": 6,
"x": 2,
"y": 1,
},
"faceMark": {
"leftEye": {"x": 33, "y": 22},
"rightEye": {"x": 44, "y": 33},
"noseTip": {"x": 43, "y": 12},
"leftMouth": {"x": 32, "y": 54},
"rightMouth": {"x": 67, "y": 12},
},
"mask": "NO",
"faceScore": 90,
},
},
},
)
elif self.path == "/api/visitor/v2/appointment/records":
self._send_json_response(
200,
{
"code": "0",
"msg": "success",
"data": {
"total": 1,
"pageNo": 1,
"pageSize": 20,
"list": [
{
"appointRecordId": "321654987",
"receptionistId": "3124126241412",
"receptionistName": "王五",
"receptionistCode": "323JH234KJH23",
"visitStartTime": "2018-07-26T15:00:00 + 08:00",
"visitEndTime": "2018-07-26T19:00:00 + 08:00",
"visitPurpose": "参考",
"visitorName": "张三",
"visitorId": "ASDF454SDAF565613JHU7712332",
"verificationCode": "1234",
"QRCode": "2015468421",
"": 1,
"phoneNo": "13576361254",
"plateNo": "浙 A12345",
"certificateType": 111,
"certificateNo": "311256196602145692",
"picUri": "/pic?adsdqwe21-asafdd-12sfsdfsdf",
"svrIndexCode": "sadsa123-asd21edsfhgsd-23rfdvsr",
"visitorStatus": 1,
"certAddr": "杭州滨江",
"certIssuer": "滨江分局",
"nation": 1,
"birthplace": "杭州",
"visitorWorkUnit": "中国工商银行",
"visitorAddress": "杭州滨江",
"orderId": "d089ady8a0dud87018d0y90ay9d901",
"designatedResources": {
"paramKey": "1",
"paramValues": ["52v72v35762587n75b26"],
},
"privilegeGroupNames": ["one"],
"identityUri": "/pic?123-scccdf334-3216516516516",
"identitySvrCode": "12ddf53ggg56sss6554",
}
],
},
},
)
elif self.path == "/api/nms/v1/online/acs_device/get":
self._send_json_response(
200,
{
"code": "0",
"msg": "success",
"data": {
"pageNo": 1,
"pageSize": 10,
"totalPage": 0,
"total": 1,
"list": [
{
"deviceType": "HIK%2FDS-9116HW-ST%2F-AF-DVR",
"deviceIndexCode": "null",
"regionIndexCode": "ce91c758-5af4-4539-845a",
"collectTime": "2018-12-28T10:21:40.000+08:00",
"regionName": "NMS 自动化",
"indexCode": "82896441ced946d5a51c6d6ca8e65851",
"cn": "Onvif-IPC(10.67.172.13 )",
"treatyType": "onvif_net",
"manufacturer": "hikvision",
"ip": "10.67.172.13",
"port": 80,
"online": 1,
}
],
},
},
)
except json.JSONDecodeError:
self._send_json_response(400, {"error": "无效的JSON数据"})
except Exception as e:
self._send_json_response(500, {"code": 0, "error": f"服务器错误: {str(e)}"})
def do_PUT(self):
"""处理PUT请求"""
content_length = int(self.headers.get("Content-Length", 0))
put_data = self.rfile.read(content_length)
logger.info(f"PUT 请求: {self.path}")
try:
data = json.loads(put_data.decode("utf-8"))
self._send_json_response(200, {"message": "数据已更新", "data": data})
except json.JSONDecodeError:
self._send_json_response(400, {"error": "无效的JSON数据"})
def do_DELETE(self):
"""处理DELETE请求"""
logger.info(f"DELETE 请求: {self.path}")
self._send_json_response(200, {"message": "删除成功", "path": self.path})
def _handle_user_api(self, query_params):
"""处理用户API请求"""
user_id = query_params.get("id", [""])[0]
if user_id:
user_data = {
"id": user_id,
"name": f"用户{user_id}",
"email": f"user{user_id}@example.com",
"status": "active",
}
self._send_json_response(200, user_data)
else:
# 返回用户列表
users = [
{"id": "1", "name": "张三", "email": "zhangsan@example.com"},
{"id": "2", "name": "李四", "email": "lisi@example.com"},
{"id": "3", "name": "王五", "email": "wangwu@example.com"},
]
self._send_json_response(200, {"users": users})
def _handle_login(self, data):
"""处理登录请求"""
username = (
data.get("username", [""])[0]
if isinstance(data, dict)
else data.get("username", "")
)
password = (
data.get("password", [""])[0]
if isinstance(data, dict)
else data.get("password", "")
)
# 简单的用户验证(仅做演示)
if username == "admin" and password == "123456":
response_data = {
"success": True,
"message": "登录成功",
"token": "fake_jwt_token_here",
"user": {"username": username, "role": "admin"},
}
self._send_json_response(200, response_data)
else:
self._send_json_response(
401, {"success": False, "message": "用户名或密码错误"}
)
def _send_response(self, status_code, content_type, content):
"""发送HTTP响应"""
self.send_response(status_code)
self.send_header("Content-Type", f"{content_type}; charset=utf-8")
self.send_header("Access-Control-Allow-Origin", "*") # 允许跨域
self.send_header(
"Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"
)
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
self.wfile.write(content.encode("utf-8"))
def _send_json_response(self, status_code, data):
"""发送JSON响应"""
json_data = json.dumps(data, ensure_ascii=False, indent=2)
self._send_response(status_code, "application/json", json_data)
def _get_home_page(self):
"""获取首页HTML"""
return """
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Python HTTP 服务端</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.api-list { background: #f5f5f5; padding: 20px; border-radius: 5px; }
.api-item { margin: 10px 0; padding: 10px; background: white; border-radius: 3px; }
.method { font-weight: bold; color: #007cba; }
</style>
</head>
<body>
<h1>🚀 Python HTTP 服务端</h1>
<p>服务运行成功以下是可用的API接口</p>
<div class="api-list">
<div class="api-item">
<span class="method">GET</span> /api/status - 获取服务状态
</div>
<div class="api-item">
<span class="method">GET</span> /api/time - 获取当前时间
</div>
<div class="api-item">
<span class="method">GET</span> /api/user - 获取用户列表
</div>
<div class="api-item">
<span class="method">GET</span> /api/user?id=1 - 获取指定用户
</div>
<div class="api-item">
<span class="method">POST</span> /api/login - 用户登录 (username: admin, password: 123456)
</div>
<div class="api-item">
<span class="method">POST</span> /api/echo - 回显接收到的数据
</div>
</div>
<h3>测试示例</h3>
<pre>
# 获取状态
curl http://localhost:8080/api/status
# 用户登录
curl -X POST -H "Content-Type: application/json" \\
-d '{"username":"admin","password":"123456"}' \\
http://localhost:8080/api/login
# 获取用户信息
curl http://localhost:8080/api/user?id=1
</pre>
</body>
</html>
"""
def do_OPTIONS(self):
"""处理预检请求CORS"""
self.send_response(200)
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header(
"Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"
)
self.send_header("Access-Control-Allow-Headers", "Content-Type")
self.end_headers()
def log_message(self, format, *args):
"""自定义日志格式"""
logger.info(f"{self.address_string()} - {format % args}")
def run_server(host="localhost", port=8080):
"""启动HTTP服务器"""
server_address = (host, port)
httpd = HTTPServer(server_address, CustomHTTPRequestHandler)
print(f"🌟 HTTP服务器启动成功!")
print(f"📍 地址: http://{host}:{port}")
print(f"🔗 在浏览器中访问: http://{host}:{port}")
print(f"⏹️ 按 Ctrl+C 停止服务器\n")
try:
httpd.serve_forever()
except KeyboardInterrupt:
print("\n🛑 服务器已停止")
httpd.server_close()
if __name__ == "__main__":
# 启动服务器
run_server(host="10.0.0.202", port=9909)

View File

@ -0,0 +1,11 @@
from urllib.parse import urlparse
url = "https://192.168.10.251:8001/artemis/test_v1"
parsed = urlparse(url)
path_and_query = parsed.path
if parsed.query:
path_and_query += "?" + parsed.query
print(path_and_query)

View File

@ -0,0 +1,57 @@
from utils.compreface_util import ComprefaceUtil
import asyncio
import time
import json
image_path = "./haotian1.jpg"
with open(image_path, "rb") as f:
image_bytes = f.read() # 获取图片的字节流
# # 测试上传人脸图片
print(asyncio.run(ComprefaceUtil.face_addition(image_path, '刘昊天_访客')))
# #-----------------------------------------测试人脸识别--------------------------------------------
# start_time = time.time()
# result = asyncio.run(
# ComprefaceUtil.face_recognition(
# image_bytes,
# options={
# "limit": 0,
# "det_prob_threshold": 0.8,
# "prediction_count": 1,
# # 可选参数 age,gender,landmarks,calculator
# "face_plugins": "gender",
# "status": "true",
# },
# )
# )
# print(result)
# with open("compreface_face_recognition.json", "w", encoding="utf-8") as f:
# f.write(json.dumps(result, ensure_ascii=False, indent=4))
# print("spend time:", time.time() - start_time)
# #-----------------------------------------测试人脸识别end------------------------------------------
# # -----------------------------------------测试人脸检测--------------------------------------------
# start_time = time.time()
# result = asyncio.run(
# ComprefaceUtil.face_detection(
# image_bytes,
# options={
# "limit": 0,
# "det_prob_threshold": 0.8,
# "prediction_count": 1,
# # 可选参数 age,gender,landmarks,calculator
# "face_plugins": "pose",
# "status": "false",
# }
# )
# )
# print(result)
# with open("compreface_face_detection.json", "w", encoding="utf-8") as f:
# f.write(json.dumps(result, ensure_ascii=False, indent=4))
# print("spend time:", time.time() - start_time)
# # -----------------------------------------测试人脸检测end-----------------------------------------

View File

@ -0,0 +1,56 @@
import requests
from compreface import CompreFace
from compreface.service import RecognitionService, DetectionService
from compreface.collections import FaceCollection
from compreface.collections.face_collections import Subjects
import time
DOMAIN: str = 'http://localhost'
PORT: str = '8000'
def face_recognition_stream(image_path, url):
with open(image_path, 'rb') as f:
response = requests.post(url, data=f.read())
return response.json()
def face_recognition_file(image_path, url):
files = {"file": ("test.jpg", open(image_path, "rb"), "image/jpeg")}
response = requests.post(url, files=files)
return response.json()
def face_recognition_compreface(image_path):
API_KEY: str = 'a5924457-62c9-47dc-a6e7-15462c502d2c'
compre_face: CompreFace = CompreFace(DOMAIN, PORT)
recognition: RecognitionService = compre_face.init_face_recognition(API_KEY)
start_time = time.time()
result = recognition.recognize(image_path=image_path)
print("--- %s seconds ---" % (time.time() - start_time))
print(result)
def face_detection_compreface(image_path):
API_KEY: str = '070283a2-faa3-423b-9772-2cd48ecc5362'
compre_face: CompreFace = CompreFace(DOMAIN, PORT)
detection: DetectionService = compre_face.init_face_detection(API_KEY)
start_time = time.time()
result = detection.detect(image_path=image_path)
print("--- %s seconds ---" % (time.time() - start_time))
print(result)
if __name__ == '__main__':
image_path = './moshengren.jpg'
url = 'http://10.0.0.202:9099/system/compreface/face_recognition'
# print(face_recognition_stream(image_path, url))
# print(face_recognition_file(image_path, url))
# face_recognition_compreface(image_path)
face_detection_compreface(image_path)

View File

@ -0,0 +1,25 @@
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
import datetime
import time
def my_job():
print("任务执行时间:", datetime.datetime.now())
if __name__ == '__main__':
scheduler = BlockingScheduler(timezone="Asia/Shanghai")
# # 每天凌晨 1 点执行
# scheduler.add_job(my_job, trigger="cron", hour=1, minute=0)
# 或者用 CronTrigger
trigger = CronTrigger(minute='*', second=0)
scheduler.add_job(my_job, trigger=trigger)
scheduler.start()
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
scheduler.shutdown()

View File

@ -0,0 +1,5 @@
import os
txt_path = "./test/image_base64.txt"
print(os.path.dirname(txt_path))
# os.makedirs(, exist_ok=True)

View File

@ -0,0 +1,49 @@
import asyncio
from utils.haikang_util import HaikangUtil
async def get_all_employee_pictures(pageNo=2, pageSize=1000):
result = await HaikangUtil.get_person_list(pageNo=pageNo, pageSize=pageSize)
print(result)
employee_list = list()
if result[0]:
total = result[1]['total']
employee_list += result[1]['list']
while pageNo * pageSize < total:
pageNo += 1
result = await HaikangUtil.get_person_list(pageNo=pageNo + 1, pageSize=pageSize, )
if result[0]:
employee_list += result[1]['list']
else:
break
with open("./employee/personIds.txt", "r", encoding="utf-8") as f:
person_ids = [line.rstrip('\n') for line in f]
# print(visitor_ids)
person_ids_add = list()
for employee in employee_list:
# print(employee)
if employee["personId"] not in person_ids:
person_ids_add.append(employee["personId"])
# 获取图片
try:
await HaikangUtil.get_person_picture(employee.get("personPhoto")[0]["serverIndexCode"], employee.get("personPhoto")[0]["picUri"], f"./employee/face_images/{employee['personName']}")
await asyncio.sleep(0.5)
except Exception as e:
print(f"error: {e}, personId: {employee['personId']}")
with open("./employee/personIds.txt", "a", encoding="utf-8") as f:
for person_id in person_ids_add:
f.write(person_id + "\n")
if __name__ == '__main__':
asyncio.run(get_all_employee_pictures())

View File

@ -0,0 +1,24 @@
from utils.compreface_util import ComprefaceUtil
import asyncio
import os
if __name__ == '__main__':
image_path = "/root/robot_project/kangda-robot-backend-master/ruoyi-fastapi-backend/employee/face_images"
person_name = os.listdir(image_path)
for person in person_name:
image_list = os.listdir(os.path.join(image_path, person))
for image in image_list:
t = os.path.join(image_path, person, image)
try:
asyncio.run(ComprefaceUtil.face_addition(t, person))
except Exception as e:
print(e)
print(f"error: {person}")
# break

View File

@ -0,0 +1,143 @@
import os
import requests
from pathlib import Path
# CompreFace配置
# COMPREFACE_BASE_URL = "http://localhost"
# COMPERFACE_BASE_PORT = "9900"
# COMPREFACE_API_KEY = "9115667c-4968-400f-9006-7b2646fba8df"
# COMPREFACE_API_KEY_DETECTION = "08f31eab-de28-4c00-aea5-eb69f2619783"
COMPREFACE_URL = "http://localhost:9900" # 修改为你的CompreFace地址
API_KEY = "9115667c-4968-400f-9006-7b2646fba8df" # 修改为你的API Key
RECOGNITION_API = f"{COMPREFACE_URL}/api/v1/recognition"
# 图片目录
FACE_IMAGES_DIR = "employee/face_images"
def get_all_subjects():
"""获取人脸库中所有已存在的subject人名"""
headers = {"x-api-key": API_KEY}
try:
response = requests.get(f"{RECOGNITION_API}/subjects", headers=headers)
response.raise_for_status()
data = response.json()
return data.get("subjects", [])
except Exception as e:
print(f"获取subjects列表失败: {e}")
return []
def get_subject_faces(subject):
"""获取指定subject的所有人脸图片"""
headers = {"x-api-key": API_KEY}
try:
response = requests.get(
f"{RECOGNITION_API}/faces",
headers=headers,
params={"subject": subject}
)
response.raise_for_status()
data = response.json()
return data.get("faces", [])
except Exception as e:
print(f"获取{subject}的人脸列表失败: {e}")
return []
def upload_face(subject, image_path):
"""上传人脸图片到CompreFace"""
headers = {"x-api-key": API_KEY}
try:
with open(image_path, "rb") as image_file:
files = {"file": image_file}
params = {"subject": subject}
response = requests.post(
f"{RECOGNITION_API}/faces",
headers=headers,
params=params,
files=files
)
response.raise_for_status()
return True, response.json()
except Exception as e:
return False, str(e)
def main():
# 检查目录是否存在
if not os.path.exists(FACE_IMAGES_DIR):
print(f"错误: 目录 {FACE_IMAGES_DIR} 不存在")
return
# 获取已存在的subjects
print("正在获取人脸库中已存在的人员...")
existing_subjects = get_all_subjects()
print(f"人脸库中已有 {len(existing_subjects)} 个人员")
# 创建已存在人脸的映射subject -> face count
existing_faces = {}
for subject in existing_subjects:
faces = get_subject_faces(subject)
existing_faces[subject] = len(faces)
print(f" - {subject}: {len(faces)} 张图片")
print("\n开始处理本地图片...")
# 统计信息
total_images = 0
uploaded_count = 0
skipped_count = 0
failed_count = 0
# 遍历目录
for person_dir in Path(FACE_IMAGES_DIR).iterdir():
if not person_dir.is_dir():
continue
subject = person_dir.name
print(f"\n处理人员: {subject}")
# 获取该人员的所有图片
image_files = list(person_dir.glob("*.jpg")) + \
list(person_dir.glob("*.jpeg")) + \
list(person_dir.glob("*.png"))
total_images += len(image_files)
# 检查是否已在库中
if subject in existing_faces:
# 如果库中已有足够的图片,跳过
if existing_faces[subject] >= len(image_files):
print(f" ✓ 已存在 {existing_faces[subject]} 张图片,跳过上传")
skipped_count += len(image_files)
continue
else:
print(f" 库中已有 {existing_faces[subject]} 张,本地有 {len(image_files)}")
# 上传图片
for image_path in image_files:
print(f" 上传: {image_path.name}...", end=" ")
success, result = upload_face(subject, str(image_path))
if success:
print("✓ 成功")
uploaded_count += 1
else:
print(f"✗ 失败: {result}")
failed_count += 1
# 输出统计信息
print("\n" + "="*50)
print("上传完成!")
print(f"总图片数: {total_images}")
print(f"成功上传: {uploaded_count}")
print(f"跳过: {skipped_count}")
print(f"失败: {failed_count}")
print("="*50)
if __name__ == "__main__":
main()

View File

@ -1,483 +0,0 @@
from config.env import DataBaseConfig
class CommonConstant:
"""
常用常量
WWW: www主域
HTTP: http请求
HTTPS: https请求
LOOKUP_RMI: RMI远程方法调用
LOOKUP_LDAP: LDAP远程方法调用
LOOKUP_LDAPS: LDAPS远程方法调用
YES: 是否为系统默认
NO: 是否为系统默认
DEPT_NORMAL: 部门正常状态
DEPT_DISABLE: 部门停用状态
UNIQUE: 校验是否唯一的返回标识
NOT_UNIQUE: 校验是否唯一的返回标识
"""
WWW = 'www.'
HTTP = 'http://'
HTTPS = 'https://'
LOOKUP_RMI = 'rmi:'
LOOKUP_LDAP = 'ldap:'
LOOKUP_LDAPS = 'ldaps:'
YES = 'Y'
NO = 'N'
DEPT_NORMAL = '0'
DEPT_DISABLE = '1'
UNIQUE = True
NOT_UNIQUE = False
class HttpStatusConstant:
"""
返回状态码
SUCCESS: 操作成功
CREATED: 对象创建成功
ACCEPTED: 请求已经被接受
NO_CONTENT: 操作已经执行成功但是没有返回数据
MOVED_PERM: 资源已被移除
SEE_OTHER: 重定向
NOT_MODIFIED: 资源没有被修改
BAD_REQUEST: 参数列表错误缺少格式不匹配
UNAUTHORIZED: 未授权
FORBIDDEN: 访问受限授权过期
NOT_FOUND: 资源服务未找到
BAD_METHOD: 不允许的http方法
CONFLICT: 资源冲突或者资源被锁
UNSUPPORTED_TYPE: 不支持的数据媒体类型
ERROR: 系统内部错误
NOT_IMPLEMENTED: 接口未实现
WARN: 系统警告消息
"""
SUCCESS = 200
CREATED = 201
ACCEPTED = 202
NO_CONTENT = 204
MOVED_PERM = 301
SEE_OTHER = 303
NOT_MODIFIED = 304
BAD_REQUEST = 400
UNAUTHORIZED = 401
FORBIDDEN = 403
NOT_FOUND = 404
BAD_METHOD = 405
CONFLICT = 409
UNSUPPORTED_TYPE = 415
ERROR = 500
NOT_IMPLEMENTED = 501
WARN = 601
class JobConstant:
"""
定时任务常量
JOB_ERROR_LIST: 定时任务禁止调用模块及违规字符串列表
JOB_WHITE_LIST: 定时任务允许调用模块列表
"""
JOB_ERROR_LIST = [
'app',
'config',
'exceptions',
'import ',
'middlewares',
'module_admin',
'open(',
'os.',
'server',
'sub_applications',
'subprocess.',
'sys.',
'utils',
'while ',
'__import__',
'"',
"'",
',',
'?',
':',
';',
'/',
'|',
'+',
'-',
'=',
'~',
'!',
'#',
'$',
'%',
'^',
'&',
'*',
'<',
'>',
'(',
')',
'[',
']',
'{',
'}',
' ',
]
JOB_WHITE_LIST = ['module_task']
class MenuConstant:
"""
菜单常量
TYPE_DIR: 菜单类型目录
TYPE_MENU: 菜单类型菜单
TYPE_BUTTON: 菜单类型按钮
YES_FRAME: 是否菜单外链
NO_FRAME: 是否菜单外链
LAYOUT: Layout组件标识
PARENT_VIEW: ParentView组件标识
INNER_LINK: InnerLink组件标识
"""
TYPE_DIR = 'M'
TYPE_MENU = 'C'
TYPE_BUTTON = 'F'
YES_FRAME = 0
NO_FRAME = 1
LAYOUT = 'Layout'
PARENT_VIEW = 'ParentView'
INNER_LINK = 'InnerLink'
class GenConstant:
"""
代码生成常量
TPL_CRUD: 单表增删改查
TPL_TREE: 树表增删改查
TPL_SUB: 主子表增删改查
TREE_CODE: 树编码字段
TREE_PARENT_CODE: 树父编码字段
TREE_NAME: 树名称字段
PARENT_MENU_ID: 上级菜单ID字段
PARENT_MENU_NAME: 上级菜单名称字段
COLUMNTYPE_STR: 数据库字符串类型
COLUMNTYPE_TEXT: 数据库文本类型
COLUMNTYPE_TIME: 数据库时间类型
COLUMNTYPE_GEOMETRY: 数据库字空间类型
COLUMNTYPE_NUMBER: 数据库数字类型
COLUMNNAME_NOT_EDIT: 页面不需要编辑字段
COLUMNNAME_NOT_LIST: 页面不需要显示的列表字段
COLUMNNAME_NOT_QUERY: 页面不需要查询字段
BASE_ENTITY: Entity基类字段
TREE_ENTITY: Tree基类字段
HTML_INPUT: 文本框
HTML_TEXTAREA: 文本域
HTML_SELECT: 下拉框
HTML_RADIO: 单选框
HTML_CHECKBOX: 复选框
HTML_DATETIME: 日期控件
HTML_IMAGE_UPLOAD: 图片上传控件
HTML_FILE_UPLOAD: 文件上传控件
HTML_EDITOR: 富文本控件
TYPE_DECIMAL: 高精度计算类型
TYPE_DATE: 时间类型
QUERY_LIKE: 模糊查询
QUERY_EQ: 相等查询
REQUIRE: 需要
DB_TO_SQLALCHEMY_TYPE_MAPPING: 数据库类型与sqlalchemy类型映射
DB_TO_PYTHON_TYPE_MAPPING: 数据库类型与python类型映射
"""
TPL_CRUD = 'crud'
TPL_TREE = 'tree'
TPL_SUB = 'sub'
TREE_CODE = 'treeCode'
TREE_PARENT_CODE = 'treeParentCode'
TREE_NAME = 'treeName'
PARENT_MENU_ID = 'parentMenuId'
PARENT_MENU_NAME = 'parentMenuName'
COLUMNTYPE_STR = (
['character varying', 'varchar', 'character', 'char']
if DataBaseConfig.db_type == 'postgresql'
else ['char', 'varchar', 'nvarchar', 'varchar2']
)
COLUMNTYPE_TEXT = (
['text', 'citext'] if DataBaseConfig.db_type == 'postgresql' else ['tinytext', 'text', 'mediumtext', 'longtext']
)
COLUMNTYPE_TIME = (
[
'date',
'time',
'time with time zone',
'time without time zone',
'timestamp',
'timestamp with time zone',
'timestamp without time zone',
'interval',
]
if DataBaseConfig.db_type == 'postgresql'
else ['datetime', 'time', 'date', 'timestamp']
)
COLUMNTYPE_GEOMETRY = (
['point', 'line', 'lseg', 'box', 'path', 'polygon', 'circle']
if DataBaseConfig.db_type == 'postgresql'
else [
'geometry',
'point',
'linestring',
'polygon',
'multipoint',
'multilinestring',
'multipolygon',
'geometrycollection',
]
)
COLUMNTYPE_NUMBER = [
'tinyint',
'smallint',
'mediumint',
'int',
'number',
'integer',
'bit',
'bigint',
'float',
'double',
'decimal',
]
COLUMNNAME_NOT_ADD_SHOW = ['create_by', 'create_time']
COLUMNNAME_NOT_EDIT_SHOW = ['update_by', 'update_time']
COLUMNNAME_NOT_EDIT = ['id', 'create_by', 'create_time', 'del_flag']
COLUMNNAME_NOT_LIST = ['id', 'create_by', 'create_time', 'del_flag', 'update_by', 'update_time']
COLUMNNAME_NOT_QUERY = ['id', 'create_by', 'create_time', 'del_flag', 'update_by', 'update_time', 'remark']
BASE_ENTITY = ['createBy', 'createTime', 'updateBy', 'updateTime', 'remark']
TREE_ENTITY = ['parentName', 'parentId', 'orderNum', 'ancestors', 'children']
HTML_INPUT = 'input'
HTML_TEXTAREA = 'textarea'
HTML_SELECT = 'select'
HTML_RADIO = 'radio'
HTML_CHECKBOX = 'checkbox'
HTML_DATETIME = 'datetime'
HTML_IMAGE_UPLOAD = 'imageUpload'
HTML_FILE_UPLOAD = 'fileUpload'
HTML_EDITOR = 'editor'
TYPE_DECIMAL = 'Decimal'
TYPE_DATE = ['date', 'time', 'datetime']
QUERY_LIKE = 'LIKE'
QUERY_EQ = 'EQ'
REQUIRE = '1'
DB_TO_SQLALCHEMY_TYPE_MAPPING = (
{
'boolean': 'Boolean',
'smallint': 'SmallInteger',
'integer': 'Integer',
'bigint': 'BigInteger',
'real': 'Float',
'double precision': 'Float',
'numeric': 'Numeric',
'character varying': 'String',
'character': 'String',
'text': 'Text',
'bytea': 'LargeBinary',
'date': 'Date',
'time': 'Time',
'time with time zone': 'Time',
'time without time zone': 'Time',
'timestamp': 'DateTime',
'timestamp with time zone': 'DateTime',
'timestamp without time zone': 'DateTime',
'interval': 'Interval',
'json': 'JSON',
'jsonb': 'JSONB',
'uuid': 'Uuid',
'inet': 'INET',
'cidr': 'CIDR',
'macaddr': 'MACADDR',
'point': 'Geometry',
'line': 'Geometry',
'lseg': 'Geometry',
'box': 'Geometry',
'path': 'Geometry',
'polygon': 'Geometry',
'circle': 'Geometry',
'bit': 'Bit',
'bit varying': 'Bit',
'tsvector': 'TSVECTOR',
'tsquery': 'TSQUERY',
'xml': 'String',
'array': 'ARRAY',
'composite': 'JSON',
'enum': 'Enum',
'range': 'Range',
'money': 'Numeric',
'pg_lsn': 'BigInteger',
'txid_snapshot': 'String',
'oid': 'BigInteger',
'regproc': 'String',
'regclass': 'String',
'regtype': 'String',
'regrole': 'String',
'regnamespace': 'String',
'int2vector': 'ARRAY',
'oidvector': 'ARRAY',
'pg_node_tree': 'Text',
}
if DataBaseConfig.db_type == 'postgresql'
else {
# 数值类型
'TINYINT': 'SmallInteger',
'SMALLINT': 'SmallInteger',
'MEDIUMINT': 'Integer',
'INT': 'Integer',
'INTEGER': 'Integer',
'BIGINT': 'BigInteger',
'FLOAT': 'Float',
'DOUBLE': 'Float',
'DECIMAL': 'DECIMAL',
'BIT': 'Integer',
# 日期和时间类型
'DATE': 'Date',
'TIME': 'Time',
'DATETIME': 'DateTime',
'TIMESTAMP': 'TIMESTAMP',
'YEAR': 'Integer',
# 字符串类型
'CHAR': 'CHAR',
'VARCHAR': 'String',
'TINYTEXT': 'Text',
'TEXT': 'Text',
'MEDIUMTEXT': 'Text',
'LONGTEXT': 'Text',
'BINARY': 'BINARY',
'VARBINARY': 'VARBINARY',
'TINYBLOB': 'LargeBinary',
'BLOB': 'LargeBinary',
'MEDIUMBLOB': 'LargeBinary',
'LONGBLOB': 'LargeBinary',
# 枚举和集合类型
'ENUM': 'Enum',
'SET': 'String',
# JSON 类型
'JSON': 'JSON',
# 空间数据类型(需要扩展支持,如 GeoAlchemy2
'GEOMETRY': 'Geometry', # 需要安装 geoalchemy2
'POINT': 'Geometry',
'LINESTRING': 'Geometry',
'POLYGON': 'Geometry',
'MULTIPOINT': 'Geometry',
'MULTILINESTRING': 'Geometry',
'MULTIPOLYGON': 'Geometry',
'GEOMETRYCOLLECTION': 'Geometry',
}
)
DB_TO_PYTHON_TYPE_MAPPING = (
{
'boolean': 'bool',
'smallint': 'int',
'integer': 'int',
'bigint': 'int',
'real': 'float',
'double precision': 'float',
'numeric': 'Decimal',
'character varying': 'str',
'character': 'str',
'text': 'str',
'bytea': 'bytes',
'date': 'date',
'time': 'time',
'time with time zone': 'time',
'time without time zone': 'time',
'timestamp': 'datetime',
'timestamp with time zone': 'datetime',
'timestamp without time zone': 'datetime',
'interval': 'timedelta',
'json': 'dict',
'jsonb': 'dict',
'uuid': 'str',
'inet': 'str',
'cidr': 'str',
'macaddr': 'str',
'point': 'list',
'line': 'list',
'lseg': 'list',
'box': 'list',
'path': 'list',
'polygon': 'list',
'circle': 'list',
'bit': 'int',
'bit varying': 'int',
'tsvector': 'str',
'tsquery': 'str',
'xml': 'str',
'array': 'list',
'composite': 'dict',
'enum': 'str',
'range': 'list',
'money': 'Decimal',
'pg_lsn': 'int',
'txid_snapshot': 'str',
'oid': 'int',
'regproc': 'str',
'regclass': 'str',
'regtype': 'str',
'regrole': 'str',
'regnamespace': 'str',
'int2vector': 'list',
'oidvector': 'list',
'pg_node_tree': 'str',
}
if DataBaseConfig.db_type == 'postgresql'
else {
# 数值类型
'TINYINT': 'int',
'SMALLINT': 'int',
'MEDIUMINT': 'int',
'INT': 'int',
'INTEGER': 'int',
'BIGINT': 'int',
'FLOAT': 'float',
'DOUBLE': 'float',
'DECIMAL': 'Decimal',
'BIT': 'int',
# 日期和时间类型
'DATE': 'date',
'TIME': 'time',
'DATETIME': 'datetime',
'TIMESTAMP': 'datetime',
'YEAR': 'int',
# 字符串类型
'CHAR': 'str',
'VARCHAR': 'str',
'TINYTEXT': 'str',
'TEXT': 'str',
'MEDIUMTEXT': 'str',
'LONGTEXT': 'str',
'BINARY': 'bytes',
'VARBINARY': 'bytes',
'TINYBLOB': 'bytes',
'BLOB': 'bytes',
'MEDIUMBLOB': 'bytes',
'LONGBLOB': 'bytes',
# 枚举和集合类型
'ENUM': 'str',
'SET': 'str',
# JSON 类型
'JSON': 'dict',
# 空间数据类型(通常需要特殊处理)
'GEOMETRY': 'bytes',
'POINT': 'bytes',
'LINESTRING': 'bytes',
'POLYGON': 'bytes',
'MULTIPOINT': 'bytes',
'MULTILINESTRING': 'bytes',
'MULTIPOLYGON': 'bytes',
'GEOMETRYCOLLECTION': 'bytes',
}
)

View File

@ -1,30 +0,0 @@
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.ext.asyncio import AsyncAttrs
from sqlalchemy.orm import DeclarativeBase
from urllib.parse import quote_plus
from config.env import DataBaseConfig
ASYNC_SQLALCHEMY_DATABASE_URL = (
f'mysql+asyncmy://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@'
f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}'
)
if DataBaseConfig.db_type == 'postgresql':
ASYNC_SQLALCHEMY_DATABASE_URL = (
f'postgresql+asyncpg://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@'
f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}'
)
async_engine = create_async_engine(
ASYNC_SQLALCHEMY_DATABASE_URL,
echo=DataBaseConfig.db_echo,
max_overflow=DataBaseConfig.db_max_overflow,
pool_size=DataBaseConfig.db_pool_size,
pool_recycle=DataBaseConfig.db_pool_recycle,
pool_timeout=DataBaseConfig.db_pool_timeout,
)
AsyncSessionLocal = async_sessionmaker(autocommit=False, autoflush=False, bind=async_engine)
class Base(AsyncAttrs, DeclarativeBase):
pass

View File

@ -1,78 +0,0 @@
from enum import Enum
class GuideWordType(Enum):
"""
引导词类型
NEWVISITOR 新访客 0
BOOKEDVISITOR 已预约访客 1
STAFF 员工 2
CHAT 聊天关键词 3
"""
NEWVISITOR = 0
BOOKEDVISITOR = 1
STAFF = 2
CHAT = 3
class ExplanationContentStatus(Enum):
"""
讲解内容状态
NOTSTART: 未开始
READY: 已就绪
PLAYING: 播放中
FINISH: 已完成
"""
NOTSTART = '0'
READY = '1'
PLAYING = '2'
FINISH = '3'
class BusinessType(Enum):
"""
业务操作类型
OTHER: 其它
INSERT: 新增
UPDATE: 修改
DELETE: 删除
GRANT: 授权
EXPORT: 导出
IMPORT: 导入
FORCE: 强退
GENCODE: 生成代码
CLEAN: 清空数据
"""
OTHER = 0
INSERT = 1
UPDATE = 2
DELETE = 3
GRANT = 4
EXPORT = 5
IMPORT = 6
FORCE = 7
GENCODE = 8
CLEAN = 9
class RedisInitKeyConfig(Enum):
"""
系统内置Redis键名
"""
@property
def key(self):
return self.value.get('key')
@property
def remark(self):
return self.value.get('remark')
ACCESS_TOKEN = {'key': 'access_token', 'remark': '登录令牌信息'}
SYS_DICT = {'key': 'sys_dict', 'remark': '数据字典'}
SYS_CONFIG = {'key': 'sys_config', 'remark': '配置信息'}
CAPTCHA_CODES = {'key': 'captcha_codes', 'remark': '图片验证码'}
ACCOUNT_LOCK = {'key': 'account_lock', 'remark': '用户锁定'}
PASSWORD_ERROR_COUNT = {'key': 'password_error_count', 'remark': '密码错误次数'}
SMS_CODE = {'key': 'sms_code', 'remark': '短信验证码'}

View File

@ -1,463 +0,0 @@
import argparse
import os
import sys
from dotenv import load_dotenv
from functools import lru_cache
from pydantic import computed_field
from pydantic_settings import BaseSettings
from typing import Literal, Optional
from pathlib import Path
class AppSettings(BaseSettings):
"""
应用配置
"""
app_env: str = 'dev'
app_name: str = 'RuoYi-FasAPI'
app_root_path: str = '/dev-api'
app_host: str = '0.0.0.0'
app_port: int = 9099
app_version: str = '1.0.0'
app_reload: bool = False
app_ip_location_query: bool = True
app_same_time_login: bool = True
app_docs_url: Optional[str] = None
app_redoc_url: Optional[str] = None
app_openapi_url: Optional[str] = None
class JwtSettings(BaseSettings):
"""
Jwt配置
"""
jwt_secret_key: str = os.getenv('JWT_SECRET_KEY', '')
jwt_algorithm: str = os.getenv('JWT_ALGORITHM', 'HS256')
jwt_expire_minutes: int = int(os.getenv('JWT_EXPIRE_MINUTES', '1440'))
jwt_redis_expire_minutes: int = int(os.getenv('JWT_REDIS_EXPIRE_MINUTES', '30'))
class DataBaseSettings(BaseSettings):
"""
数据库配置
"""
db_type: Literal['mysql', 'postgresql'] = os.getenv('DB_TYPE', 'mysql')
db_host: str = os.getenv('DB_HOST', '127.0.0.1')
db_port: int = int(os.getenv('DB_PORT', '3306'))
db_username: str = os.getenv('DB_USERNAME', '')
db_password: str = os.getenv('DB_PASSWORD', '')
db_database: str = os.getenv('DB_DATABASE', '')
db_echo: bool = os.getenv('DB_ECHO', 'True').lower() == 'true'
db_max_overflow: int = int(os.getenv('DB_MAX_OVERFLOW', '10'))
db_pool_size: int = int(os.getenv('DB_POOL_SIZE', '50'))
db_pool_recycle: int = int(os.getenv('DB_POOL_RECYCLE', '3600'))
db_pool_timeout: int = int(os.getenv('DB_POOL_TIMEOUT', '30'))
@computed_field
@property
def sqlglot_parse_dialect(self) -> str:
if self.db_type == 'postgresql':
return 'postgres'
return self.db_type
class RedisSettings(BaseSettings):
"""
Redis配置
"""
redis_host: str = os.getenv('REDIS_HOST', '127.0.0.1')
redis_port: int = int(os.getenv('REDIS_PORT', '6379'))
redis_username: str = os.getenv('REDIS_USERNAME', '')
redis_password: str = os.getenv('REDIS_PASSWORD', '')
redis_database: int = int(os.getenv('REDIS_DATABASE', '2'))
class GenSettings:
"""
代码生成配置
"""
author = 'insistence'
package_name = 'module_admin.system'
auto_remove_pre = False
table_prefix = 'sys_'
allow_overwrite = False
GEN_PATH = 'vf_admin/gen_path'
def __init__(self):
if not os.path.exists(self.GEN_PATH):
os.makedirs(self.GEN_PATH)
class UploadSettings:
"""
上传配置
"""
UPLOAD_PREFIX = '/profile'
UPLOAD_PATH = 'vf_admin/upload_path'
UPLOAD_MACHINE = 'A'
DEFAULT_ALLOWED_EXTENSION = [
# 图片
'bmp',
'gif',
'jpg',
'jpeg',
'png',
# word excel powerpoint
'doc',
'docx',
'xls',
'xlsx',
'ppt',
'pptx',
'html',
'htm',
'txt',
# 压缩文件
'rar',
'zip',
'gz',
'bz2',
# 视频格式
'mp4',
'avi',
'rmvb',
# pdf
'pdf',
]
DOWNLOAD_PATH = 'vf_admin/download_path'
def __init__(self):
if not os.path.exists(self.UPLOAD_PATH):
os.makedirs(self.UPLOAD_PATH)
if not os.path.exists(self.DOWNLOAD_PATH):
os.makedirs(self.DOWNLOAD_PATH)
class CachePathConfig:
"""
缓存目录配置
"""
PATH = os.path.join(os.path.abspath(os.getcwd()), 'caches')
PATHSTR = 'caches'
class ComprefaceSettings:
"""
Compreface配置
"""
COMPREFACE_BASE_URL = os.getenv("COMPREFACE_BASE_URL", "http://10.0.0.202")
COMPERFACE_BASE_PORT = os.getenv("COMPERFACE_BASE_PORT", "8000")
COMPREFACE_API_KEY = os.getenv("COMPREFACE_API_KEY", "")
COMPREFACE_API_KEY_DETECTION = os.getenv("COMPREFACE_API_KEY_DETECTION", "")
COMPREFACE_FACE_FILE = os.getenv("COMPREFACE_FACE_FILE", "./image_face")
COMPREFACE_SIMILARITY_THRESHOLD = float(os.getenv("COMPREFACE_SIMILARITY_THRESHOLD", "0.995"))
COMPREFACE_POSE_MAX_ANGLE = float(os.getenv("COMPREFACE_POSE_MAX_ANGLE", "10"))
COMPREFACE_MIN_FACE_WIDTH = int(os.getenv("COMPREFACE_MIN_FACE_WIDTH", "200"))
COMPREFACE_MIN_FACE_HEIGHT = int(os.getenv("COMPREFACE_MIN_FACE_HEIGHT", "200"))
COMPREFACE_MIN_DETECTION_PROBABILITY = float(os.getenv("COMPREFACE_MIN_DETECTION_PROBABILITY", "0.9"))
class HaiKangSettings:
"""
海康平台配置
"""
HAIKANG_URL = os.getenv('HAIKANG_URL', 'https://127.0.0.1')
HAIKANG_PORT = int(os.getenv('HAIKANG_PORT', '443'))
HAIKANG_AK = os.getenv('HAIKANG_AK', '')
HAIKANG_SK = os.getenv('HAIKANG_SK', '')
HAIKANG_ACCESS_TOKEN_URL = os.getenv('HAIKANG_ACCESS_TOKEN_URL', '/api/v1/oauth/token')
# HAIKANG_DOOR_STATES_URL = '/api/v1/door/states'
HAIKANG_DOOR_STATES_URL = os.getenv('HAIKANG_DOOR_STATES_URL', '/api/acs/v1/door/states')
HAIKANG_DOOR_DOCONTROL_URL = os.getenv('HAIKANG_DOOR_DOCONTROL_URL', '/api/acs/v1/door/doControl')
HAIKANG_DOOR_ENVENTS_URL = os.getenv('HAIKANG_DOOR_EVENTS_URL', '/api/acs/v2/door/events')
HAIKANG_DOOR_SEARCH = os.getenv('HAIKANG_DOOR_SEARCH', '/api/resource/v2/door/search')
HAIKANG_DOOR_ONLINE_STATUS = os.getenv('HAIKANG_DOOR_ONLINE_STATUS', '/api/nms/v1/online/acs_device/get')
HAIKANG_APPLICATION_ONETOMANY_URL = os.getenv('HAIKANG_APPLICATION_ONETOMANY_URL', '/api/frs/v1/application/oneToMany')
HAIKANG_PICTURE_CHECK_URL = os.getenv('HAIKANG_PICTURE_CHECK_URL', '/api/frs/v1/face/picture/check')
HAIKANG_FACECAPATURE_SEARCH = os.getenv('HAIKANG_FACE_CAPTURE_SEARCH', '/api/frs/v1/event/face_capture/search')
HAIKANG_FACE_GROUP_URL = os.getenv('HAIKANG_FACE_GROUP_URL', '/api/frs/v1/face/group')
HAIKANG_VISITOR_RECORD_SEARCH = os.getenv('HAIKANG_VISITOR_RECORD_SEARCH', '/api/visitor/v2/appointment/records')
HAIKANG_VISITOR_RECORD_PICTURES = os.getenv('HAIKANG_VISITOR_RECORD_PICTURES', '/api/visitor/v1/record/pictures')
HAIKANG_PERSON_LIST = os.getenv('HAIKANG_PERSON_LIST', '/api/resource/v2/person/personList')
HAIKANG_GET_PERSON_PICTURE = os.getenv('HAIKANG_GET_PERSON_PICTURE', '/api/resource/v1/person/picture')
HAIKANG_FACE_GROUP_ADDITION = os.getenv('HAIKANG_FACE_GROUP_ADDITION', '/api/frs/v1/face/group/single/addition')
HAIKANG_FACE_SIGLE_ADDITION = os.getenv('HAIKANG_FACE_SINGLE_ADDITION', '/api/frs/v1/face/single/addition')
HAIKANG_FACE_DELETE = os.getenv('HAIKANG_FACE_DELETE', '/api/frs/v1/face/deletion')
HAIKANG_FACE_SAVE_PATH = os.getenv('HAIKANG_FACE_SAVE_PATH', "./face_images")
HAIKANG_VISITOR_PICTURES_SAVE_PATH = os.getenv('HAIKANG_VISITOR_PICTURES_SAVE_PATH', "./visitor/face_images/")
HAIKANG_VISITOR_RECORD_TXT = os.getenv('HAIKANG_VISITOR_RECORD_TXT', "./visitor/visitorIds.txt")
class RAGFlowSettings(BaseSettings):
"""
RAGFlow 配置
注意必须在 `.env.*` 加载完成后再实例化读取
所以使用 BaseSettings 而不是类常量
"""
RAGFLOW_BASE_URL: str = "http://10.0.0.202:82"
RAGFLOW_API_KEY: str = "ragflow-hlMjRmNzE2ODNiNTExZjA4ZTNlMDI0Mm"
class SearchSettings:
"""搜索服务配置"""
SEARCH_API_BASE = os.getenv("BAIDU_SEARCH_API_BASE", "https://qianfan.baidubce.com/v2/ai_search/chat/completions")
SEARCH_API_KEY = os.getenv("SEARCH_API_KEY", "")
SEARCH_ENGINE = os.getenv("SEARCH_ENGINE", "baidu")
SEARCH_LANG = os.getenv("SEARCH_LANG", "zh-cn")
SEARCH_COUNTRY = os.getenv("SEARCH_COUNTRY", "cn")
SEARCH_NUM_RESULTS = int(os.getenv("SEARCH_NUM_RESULTS", "5"))
SEARCH_CACHE_TTL = int(os.getenv("SEARCH_CACHE_TTL", "1800"))
# Baidu AppBuilder Configuration
BAIDU_APPBUILDER_API_KEY = os.getenv("BAIDU_APPBUILDER_API_KEY", "bce-v3/ALTAK-rXC12MxT2UeVrJP2S5kMJ/e42eb37b3c345e9bfb3e2eb0dcac8004888592f3")
# ZhipuAI Configuration
ZHIPUAI_API_KEY = os.getenv("ZHIPUAI_API_KEY", "c86394f9af6f4d4ebecf3f6105d3483e.tn3vZmeVB8IzO6i3")
ZHIPUAI_API_BASE = os.getenv("ZHIPUAI_API_BASE", "https://open.bigmodel.cn/api/paas/v4/chat/completions")
class DeepSeekSettings:
"""DeepSeek大语言模型配置"""
DEEPSEEK_API_BASE = os.getenv("DEEPSEEK_API_BASE", "https://api.deepseek.com")
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY", "sk-56b608b26a6949e4b09b5bf5f11c8f5b")
DEEPSEEK_MODEL = os.getenv("DEEPSEEK_MODEL", "deepseek-chat")
class KBSettings(BaseSettings):
"""内部知识库 Provider 配置ragflow / es_bm25
注意必须在 `.env.*` 加载完成后再实例化读取
所以使用 BaseSettings 而不是在 import 时读取环境变量
"""
KB_PROVIDER: Literal['ragflow', 'es_bm25'] = 'ragflow' # type: ignore[assignment]
# ES/OpenSearch
KB_ES_URL: str = ''
KB_ES_INDEX: str = 'kb_chunks_v1'
KB_ES_USERNAME: str = ''
KB_ES_PASSWORD: str = ''
KB_ES_VERIFY_SSL: bool = True
# retrieval
KB_TOP_K: int = 8
KB_MIN_SCORE: float = 0.0
KB_MIN_COVERAGE: float = 0.2
KB_CACHE_TTL: int = 1800 # seconds
# fallback
KB_FALLBACK: Literal['ragflow', 'none'] = 'ragflow' # type: ignore[assignment]
def model_post_init(self, __context) -> None: # type: ignore[override]
# 规范化dotenv/环境变量可能带空格/大小写
provider = (str(self.KB_PROVIDER) if self.KB_PROVIDER is not None else 'ragflow').strip().lower()
self.KB_PROVIDER = provider if provider in ('ragflow', 'es_bm25') else 'ragflow' # type: ignore[assignment]
es_url = (self.KB_ES_URL or '').strip().rstrip('/')
self.KB_ES_URL = es_url
fallback = (str(self.KB_FALLBACK) if self.KB_FALLBACK is not None else 'ragflow').strip().lower()
self.KB_FALLBACK = fallback if fallback in ('ragflow', 'none') else 'ragflow' # type: ignore[assignment]
class GetConfig:
"""
获取配置
"""
def __init__(self):
self.parse_cli_args()
@lru_cache()
def get_compreface_config(self):
"""
获取Compreface配置
"""
# 获取Compreface配置
return ComprefaceSettings()
@lru_cache()
def get_app_config(self):
"""
获取应用配置
"""
# 实例化应用配置模型
return AppSettings()
@lru_cache()
def get_jwt_config(self):
"""
获取Jwt配置
"""
# 实例化Jwt配置模型
return JwtSettings()
@lru_cache()
def get_database_config(self):
"""
获取数据库配置
"""
# 实例化数据库配置模型
return DataBaseSettings()
@lru_cache()
def get_redis_config(self):
"""
获取Redis配置
"""
# 实例化Redis配置模型
return RedisSettings()
@lru_cache()
def get_gen_config(self):
"""
获取代码生成配置
"""
# 实例化代码生成配置
return GenSettings()
@lru_cache()
def get_upload_config(self):
"""
获取数据库配置
"""
# 实例上传配置
return UploadSettings()
@lru_cache()
def get_haikang_config(self):
"""
获取海康平台配置
"""
return HaiKangSettings()
@lru_cache()
def get_ragflow_config(self):
"""
获取RAGFlow配置
"""
return RAGFlowSettings()
@lru_cache()
def get_search_config(self):
"""获取搜索配置"""
return SearchSettings()
@lru_cache()
def get_deepseek_config(self):
"""获取DeepSeek配置"""
return DeepSeekSettings()
@lru_cache()
def get_kb_config(self):
"""获取内部知识库配置"""
return KBSettings()
@staticmethod
def parse_cli_args():
"""
解析命令行参数
"""
if 'uvicorn' in sys.argv[0]:
# 使用uvicorn启动时命令行参数需要按照uvicorn的文档进行配置无法自定义参数
pass
else:
# 使用argparse定义命令行参数
parser = argparse.ArgumentParser(description='命令行参数')
parser.add_argument('--env', type=str, default='dev', help='运行环境')
# 解析命令行参数
args, _unknown = parser.parse_known_args()
# 设置环境变量如果未设置命令行参数默认APP_ENV为dev
os.environ['APP_ENV'] = args.env if args.env else 'dev'
# 读取运行环境
run_env = os.environ.get('APP_ENV', '')
# 运行环境未指定时默认加载.env.dev
env_file = '.env.dev'
# 运行环境不为空时按命令行参数加载对应.env文件
if run_env != '':
env_file = f'.env.{run_env}'
# 加载配置:优先从项目根目录读取,避免工作目录不同导致找不到 .env.*
project_root = Path(__file__).resolve().parent.parent
env_path = project_root / env_file
def manual_load_env(path: Path, *, override: bool = True) -> None:
"""
python-dotenv 对某些格式 KEY = "value"兼容性不一
这里做一个非常宽松的兜底解析确保关键配置一定能读到
"""
try:
with path.open("r", encoding="utf-8-sig") as f:
for raw_line in f:
line = raw_line.strip()
if not line or line.startswith("#"):
continue
if "=" not in line:
continue
key, val = line.split("=", 1)
key = key.strip()
val = val.strip()
if not key:
continue
# 去掉行尾注释(不处理引号内 # 的复杂情况,当前 .env 无此需求)
if "#" in val:
val = val.split("#", 1)[0].strip()
# 去掉首尾引号
if len(val) >= 2 and val[0] == val[-1] and val[0] in ("'", '"'):
val = val[1:-1]
if override or key not in os.environ:
os.environ[key] = val
except Exception:
# 兜底解析失败时不阻断启动
return
if env_path.exists():
load_dotenv(str(env_path), override=True)
# 再做一次宽松解析兜底
manual_load_env(env_path, override=True)
else:
# 兜底:保持旧行为(从当前工作目录读取)
load_dotenv(env_file, override=True)
manual_load_env(Path(env_file), override=True)
# 实例化获取配置类
get_config = GetConfig()
# 应用配置
AppConfig = get_config.get_app_config()
# Jwt配置
JwtConfig = get_config.get_jwt_config()
# 数据库配置
DataBaseConfig = get_config.get_database_config()
# Redis配置
RedisConfig = get_config.get_redis_config()
# 代码生成配置
GenConfig = get_config.get_gen_config()
# 上传配置
UploadConfig = get_config.get_upload_config()
# 海康平台配置
HaiKangConfig = get_config.get_haikang_config()
# RAGFlow配置
RAGFlowConfig = get_config.get_ragflow_config()
# compreface配置
ComprefaceConfig = get_config.get_compreface_config()
# 搜索配置
SearchConfig = get_config.get_search_config()
# DeepSeek配置
DeepSeekConfig = get_config.get_deepseek_config()
# KB Provider配置
KBConfig = get_config.get_kb_config()

View File

@ -1,24 +0,0 @@
from config.database import async_engine, AsyncSessionLocal, Base
from utils.log_util import logger
async def get_db():
"""
每一个请求处理完毕后会关闭当前连接不同的请求使用不同的连接
:return:
"""
async with AsyncSessionLocal() as current_db:
yield current_db
async def init_create_table():
"""
应用启动时初始化数据库连接
:return:
"""
logger.info('初始化数据库连接...')
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
logger.info('数据库连接成功')

View File

@ -1,77 +0,0 @@
from redis import asyncio as aioredis
from redis.exceptions import AuthenticationError, TimeoutError, RedisError
from config.database import AsyncSessionLocal
from config.env import RedisConfig
from module_admin.service.config_service import ConfigService
from module_admin.service.dict_service import DictDataService
from utils.log_util import logger
class RedisUtil:
"""
Redis相关方法
"""
@classmethod
async def create_redis_pool(cls) -> aioredis.Redis:
"""
应用启动时初始化redis连接
:return: Redis连接对象
"""
logger.info('开始连接redis...')
redis = await aioredis.from_url(
url=f'redis://{RedisConfig.redis_host}',
port=RedisConfig.redis_port,
username=RedisConfig.redis_username,
password=RedisConfig.redis_password,
db=RedisConfig.redis_database,
encoding='utf-8',
decode_responses=True,
)
try:
connection = await redis.ping()
if connection:
logger.info('redis连接成功')
else:
logger.error('redis连接失败')
except AuthenticationError as e:
logger.error(f'redis用户名或密码错误详细错误信息{e}')
except TimeoutError as e:
logger.error(f'redis连接超时详细错误信息{e}')
except RedisError as e:
logger.error(f'redis连接错误详细错误信息{e}')
return redis
@classmethod
async def close_redis_pool(cls, app):
"""
应用关闭时关闭redis连接
:param app: fastapi对象
:return:
"""
await app.state.redis.close()
logger.info('关闭redis连接成功')
@classmethod
async def init_sys_dict(cls, redis):
"""
应用启动时缓存字典表
:param redis: redis对象
:return:
"""
async with AsyncSessionLocal() as session:
await DictDataService.init_cache_sys_dict_services(session, redis)
@classmethod
async def init_sys_config(cls, redis):
"""
应用启动时缓存参数配置表
:param redis: redis对象
:return:
"""
async with AsyncSessionLocal() as session:
await ConfigService.init_cache_sys_config_services(session, redis)

View File

@ -1,279 +0,0 @@
import json
from apscheduler.events import EVENT_ALL
from apscheduler.executors.asyncio import AsyncIOExecutor
from apscheduler.executors.pool import ProcessPoolExecutor
from apscheduler.jobstores.memory import MemoryJobStore
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.combining import OrTrigger
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger
from asyncio import iscoroutinefunction
from datetime import datetime, timedelta
from sqlalchemy.engine import create_engine
from sqlalchemy.orm import sessionmaker
from typing import Union
from config.database import AsyncSessionLocal, quote_plus
from config.env import DataBaseConfig, RedisConfig
from module_admin.dao.job_dao import JobDao
from module_admin.entity.vo.job_vo import JobLogModel, JobModel
from module_admin.service.job_log_service import JobLogService
from utils.log_util import logger
import module_task # noqa: F401
# 重写Cron定时
class MyCronTrigger(CronTrigger):
@classmethod
def from_crontab(cls, expr: str, timezone=None):
values = expr.split()
if len(values) != 6 and len(values) != 7:
raise ValueError('Wrong number of fields; got {}, expected 6 or 7'.format(len(values)))
second = values[0]
minute = values[1]
hour = values[2]
if '?' in values[3]:
day = None
elif 'L' in values[5]:
day = f"last {values[5].replace('L', '')}"
elif 'W' in values[3]:
day = cls.__find_recent_workday(int(values[3].split('W')[0]))
else:
day = values[3].replace('L', 'last')
month = values[4]
if '?' in values[5] or 'L' in values[5]:
week = None
elif '#' in values[5]:
week = int(values[5].split('#')[1])
else:
week = values[5]
if '#' in values[5]:
day_of_week = int(values[5].split('#')[0]) - 1
else:
day_of_week = None
year = values[6] if len(values) == 7 else None
return cls(
second=second,
minute=minute,
hour=hour,
day=day,
month=month,
week=week,
day_of_week=day_of_week,
year=year,
timezone=timezone,
)
@classmethod
def __find_recent_workday(cls, day: int):
now = datetime.now()
date = datetime(now.year, now.month, day)
if date.weekday() < 5:
return date.day
else:
diff = 1
while True:
previous_day = date - timedelta(days=diff)
if previous_day.weekday() < 5:
return previous_day.day
else:
diff += 1
SQLALCHEMY_DATABASE_URL = (
f'mysql+pymysql://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@'
f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}'
)
if DataBaseConfig.db_type == 'postgresql':
SQLALCHEMY_DATABASE_URL = (
f'postgresql+psycopg2://{DataBaseConfig.db_username}:{quote_plus(DataBaseConfig.db_password)}@'
f'{DataBaseConfig.db_host}:{DataBaseConfig.db_port}/{DataBaseConfig.db_database}'
)
engine = create_engine(
SQLALCHEMY_DATABASE_URL,
echo=DataBaseConfig.db_echo,
max_overflow=DataBaseConfig.db_max_overflow,
pool_size=DataBaseConfig.db_pool_size,
pool_recycle=DataBaseConfig.db_pool_recycle,
pool_timeout=DataBaseConfig.db_pool_timeout,
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
job_stores = {
'default': MemoryJobStore(),
'sqlalchemy': SQLAlchemyJobStore(url=SQLALCHEMY_DATABASE_URL, engine=engine),
'redis': RedisJobStore(
**dict(
host=RedisConfig.redis_host,
port=RedisConfig.redis_port,
username=RedisConfig.redis_username,
password=RedisConfig.redis_password,
db=RedisConfig.redis_database,
)
),
}
executors = {'default': AsyncIOExecutor(), 'processpool': ProcessPoolExecutor(5)}
job_defaults = {'coalesce': False, 'max_instance': 1}
scheduler = AsyncIOScheduler()
scheduler.configure(jobstores=job_stores, executors=executors, job_defaults=job_defaults)
class SchedulerUtil:
"""
定时任务相关方法
"""
@classmethod
async def init_system_scheduler(cls):
"""
应用启动时初始化定时任务
:return:
"""
logger.info('开始启动定时任务...')
scheduler.start()
async with AsyncSessionLocal() as session:
job_list = await JobDao.get_job_list_for_scheduler(session)
for item in job_list:
cls.remove_scheduler_job(job_id=str(item.job_id))
cls.add_scheduler_job(item)
scheduler.add_listener(cls.scheduler_event_listener, EVENT_ALL)
logger.info('系统初始定时任务加载成功')
@classmethod
async def close_system_scheduler(cls):
"""
应用关闭时关闭定时任务
:return:
"""
scheduler.shutdown()
logger.info('关闭定时任务成功')
@classmethod
def get_scheduler_job(cls, job_id: Union[str, int]):
"""
根据任务id获取任务对象
:param job_id: 任务id
:return: 任务对象
"""
query_job = scheduler.get_job(job_id=str(job_id))
return query_job
@classmethod
def add_scheduler_job(cls, job_info: JobModel):
"""
根据输入的任务对象信息添加任务
:param job_info: 任务对象信息
:return:
"""
job_func = eval(job_info.invoke_target)
job_executor = job_info.job_executor
if iscoroutinefunction(job_func):
job_executor = 'default'
scheduler.add_job(
func=eval(job_info.invoke_target),
trigger=MyCronTrigger.from_crontab(job_info.cron_expression),
args=job_info.job_args.split(',') if job_info.job_args else None,
kwargs=json.loads(job_info.job_kwargs) if job_info.job_kwargs else None,
id=str(job_info.job_id),
name=job_info.job_name,
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
coalesce=True if job_info.misfire_policy == '2' else False,
max_instances=3 if job_info.concurrent == '0' else 1,
jobstore=job_info.job_group,
executor=job_executor,
)
@classmethod
def execute_scheduler_job_once(cls, job_info: JobModel):
"""
根据输入的任务对象执行一次任务
:param job_info: 任务对象信息
:return:
"""
job_func = eval(job_info.invoke_target)
job_executor = job_info.job_executor
if iscoroutinefunction(job_func):
job_executor = 'default'
job_trigger = DateTrigger()
if job_info.status == '0':
job_trigger = OrTrigger(triggers=[DateTrigger(), MyCronTrigger.from_crontab(job_info.cron_expression)])
scheduler.add_job(
func=eval(job_info.invoke_target),
trigger=job_trigger,
args=job_info.job_args.split(',') if job_info.job_args else None,
kwargs=json.loads(job_info.job_kwargs) if job_info.job_kwargs else None,
id=str(job_info.job_id),
name=job_info.job_name,
misfire_grace_time=1000000000000 if job_info.misfire_policy == '3' else None,
coalesce=True if job_info.misfire_policy == '2' else False,
max_instances=3 if job_info.concurrent == '0' else 1,
jobstore=job_info.job_group,
executor=job_executor,
)
@classmethod
def remove_scheduler_job(cls, job_id: Union[str, int]):
"""
根据任务id移除任务
:param job_id: 任务id
:return:
"""
query_job = cls.get_scheduler_job(job_id=job_id)
if query_job:
scheduler.remove_job(job_id=str(job_id))
@classmethod
def scheduler_event_listener(cls, event):
# 获取事件类型和任务ID
event_type = event.__class__.__name__
# 获取任务执行异常信息
status = '0'
exception_info = ''
if event_type == 'JobExecutionEvent' and event.exception:
exception_info = str(event.exception)
status = '1'
if hasattr(event, 'job_id'):
job_id = event.job_id
query_job = cls.get_scheduler_job(job_id=job_id)
if query_job:
query_job_info = query_job.__getstate__()
# 获取任务名称
job_name = query_job_info.get('name')
# 获取任务组名
job_group = query_job._jobstore_alias
# 获取任务执行器
job_executor = query_job_info.get('executor')
# 获取调用目标字符串
invoke_target = query_job_info.get('func')
# 获取调用函数位置参数
job_args = ','.join(query_job_info.get('args'))
# 获取调用函数关键字参数
job_kwargs = json.dumps(query_job_info.get('kwargs'))
# 获取任务触发器
job_trigger = str(query_job_info.get('trigger'))
# 构造日志消息
job_message = f"事件类型: {event_type}, 任务ID: {job_id}, 任务名称: {job_name}, 执行于{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
job_log = JobLogModel(
jobName=job_name,
jobGroup=job_group,
jobExecutor=job_executor,
invokeTarget=invoke_target,
jobArgs=job_args,
jobKwargs=job_kwargs,
jobTrigger=job_trigger,
jobMessage=job_message,
status=status,
exceptionInfo=exception_info,
createTime=datetime.now(),
)
session = SessionLocal()
JobLogService.add_job_log_services(session, job_log)
session.close()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,345 +0,0 @@
# 康达机器人系统架构文档
## 1. 系统概述
康达机器人系统是一个集机器人控制、人脸识别、门禁管理、文档检索和智能对话于一体的综合性管理平台。系统采用前后端分离架构集成了多种外部服务和AI能力为用户提供全面的机器人管理和控制解决方案。
## 2. 系统架构图
```mermaid
flowchart TD
subgraph 客户端层
Web控制台["Web控制台\n(管理界面)"]
Pad控制端["Pad控制端\n(现场操作)"]
end
subgraph 后端服务层
FastAPI["FastAPI后端服务\n(核心业务逻辑)"]
Redis["Redis缓存\n(会话、数据缓存)"]
Database[("数据库\n(MySQL/PostgreSQL)")]
end
subgraph 外部服务层
RAGFlow["RAGFlow\n(文档检索与智能对话)"]
SearchAPI["搜索API\n(SerpAPI)"]
Compreface["Compreface\n(人脸识别)"]
HaiKang["海康平台\n(门禁控制)"]
end
subgraph 设备层
Robot["机器人\n(执行动作、采集数据)"]
Door["门禁设备\n(开关控制)"]
Camera["摄像头\n(图像采集)"]
end
%% 连接关系
Web控制台 -->|HTTP请求| FastAPI
Pad控制端 -->|HTTP请求| FastAPI
FastAPI -->|读写数据| Database
FastAPI -->|缓存操作| Redis
FastAPI -->|调用接口| RAGFlow
FastAPI -->|搜索增强| SearchAPI
FastAPI -->|人脸识别| Compreface
FastAPI -->|门禁控制| HaiKang
FastAPI -->|控制指令| Robot
HaiKang -->|控制| Door
Camera -->|图像数据| Compreface
Robot -->|状态反馈| FastAPI
Door -->|状态反馈| HaiKang
HaiKang -->|状态更新| FastAPI
%% 大模型服务
RAGFlow -->|调用| LLM["大语言模型\n(云上服务)"]
SearchAPI -->|调用| SearchEngine["搜索引擎\n(第三方)"]
```
## 3. 系统组件说明
### 3.1 客户端层
#### Web控制台
- **功能**:提供系统管理、用户管理、角色管理、机器人配置、讲解内容管理等功能
- **技术**Vue.js + Element Plus
- **访问方式**:浏览器访问
#### Pad控制端
- **功能**:现场控制机器人、查看实时状态、处理识别记录
- **技术**Web应用适配Pad设备
- **访问方式**Pad浏览器或专用应用
### 3.2 后端服务层
#### FastAPI后端服务
- **核心功能**
- 提供RESTful API接口
- 处理业务逻辑
- 集成各种外部服务
- 权限管理与认证
- 系统监控与日志
- **主要模块**
- 用户管理模块
- 角色管理模块
- 机器人信息管理模块
- 机器人动作管理模块
- 门禁设备管理模块
- 识别记录管理模块
- RAGFlow文档管理模块
- 人脸识别管理模块
- 系统统计模块
#### Redis缓存
- **功能**
- 会话管理
- 数据缓存
- 分布式锁
- 消息队列(可选)
#### 数据库
- **功能**:存储系统配置、用户信息、机器人数据、识别记录等持久化数据
- **支持类型**MySQL、PostgreSQL
### 3.3 外部服务层
#### RAGFlow
- **功能**
- 文档检索与管理
- 智能对话(基于大语言模型)
- 知识库管理
- **集成方式**API调用
#### 搜索API
- **功能**
- 增强智能对话的搜索能力
- 提供实时信息查询
- **技术**SerpAPI
#### Compreface
- **功能**
- 人脸识别
- 人脸比对
- 人脸检测
- **集成方式**API调用
#### 海康平台
- **功能**
- 门禁设备管理
- 门禁状态查询
- 门禁控制(开关门)
- 门禁事件记录
- **集成方式**API调用
### 3.4 设备层
#### 机器人
- **功能**
- 执行预设动作
- 采集环境数据
- 接收并执行控制指令
- 反馈执行状态
#### 门禁设备
- **功能**
- 开关门控制
- 状态反馈
- 事件记录
#### 摄像头
- **功能**
- 图像采集
- 视频监控
- 人脸数据采集
## 4. 核心工作流程
### 4.1 用户认证流程
```mermaid
sequenceDiagram
participant 用户 as 用户
participant Web as Web控制台/Pad控制端
participant FastAPI as FastAPI后端
participant Redis as Redis缓存
participant DB as 数据库
用户->>Web: 输入用户名密码
Web->>FastAPI: POST /system/user/login
FastAPI->>DB: 查询用户信息
DB-->>FastAPI: 返回用户数据
FastAPI->>FastAPI: 验证密码
FastAPI->>Redis: 生成并存储token
Redis-->>FastAPI: 返回token
FastAPI-->>Web: 返回token和用户信息
Web->>Web: 存储token
```
### 4.2 门禁控制流程
```mermaid
sequenceDiagram
participant Pad as Pad控制端
participant FastAPI as FastAPI后端
participant HaiKang as 海康平台API
participant Door as 门禁设备
Pad->>FastAPI: POST /system/door/control_door
FastAPI->>HaiKang: 请求门禁控制
HaiKang->>Door: 发送开关指令
Door-->>HaiKang: 执行结果
HaiKang-->>FastAPI: 返回控制结果
FastAPI-->>Pad: 返回操作状态
```
### 4.3 人脸识别流程
```mermaid
sequenceDiagram
participant Camera as 摄像头
participant Compreface as Compreface
participant FastAPI as FastAPI后端
participant DB as 数据库
participant Robot as 机器人
Camera->>Compreface: 上传人脸图像
Compreface->>Compreface: 检测人脸
Compreface->>Compreface: 提取特征
Compreface->>FastAPI: 返回识别结果
FastAPI->>DB: 保存识别记录
FastAPI->>Robot: 发送响应指令
Robot-->>FastAPI: 执行结果
```
### 4.4 智能对话流程
```mermaid
sequenceDiagram
participant User as 用户
participant Web as Web/Pad客户端
participant FastAPI as FastAPI后端
participant Redis as Redis缓存
participant RAGFlow as RAGFlow
participant Search as 搜索API
participant LLM as 大语言模型
User->>Web: 输入问题
Web->>FastAPI: POST /system/ragflow/converse_with_chat_assistant
FastAPI->>Redis: 检查缓存
alt 缓存命中
Redis-->>FastAPI: 返回缓存结果
else 缓存未命中
FastAPI->>RAGFlow: 发送对话请求
RAGFlow->>Search: 检查是否需要搜索增强
alt 需要搜索增强
Search->>SearchEngine: 执行搜索
SearchEngine-->>Search: 返回搜索结果
Search-->>RAGFlow: 返回搜索内容
end
RAGFlow->>LLM: 调用大语言模型
LLM-->>RAGFlow: 返回生成内容
RAGFlow-->>FastAPI: 返回对话结果
FastAPI->>Redis: 存储结果到缓存
end
FastAPI-->>Web: 返回对话结果
Web->>User: 显示回答
```
## 5. 系统集成与依赖
### 5.1 内部依赖
| 依赖名称 | 用途 | 版本 |
|---------|------|------|
| FastAPI | 后端框架 | 最新 |
| SQLAlchemy | ORM框架 | 最新 |
| Redis | 缓存服务 | 最新 |
| Pydantic | 数据验证 | 最新 |
| python-jose | JWT认证 | 最新 |
### 5.2 外部服务依赖
| 服务名称 | 用途 | 集成方式 |
|---------|------|---------|
| RAGFlow | 文档检索与智能对话 | API调用 |
| Compreface | 人脸识别 | API调用 |
| 海康平台 | 门禁控制 | API调用 |
| SerpAPI | 搜索增强 | API调用 |
## 6. 系统特性与优势
1. **模块化设计**:系统采用模块化架构,各功能模块独立,便于维护和扩展
2. **前后端分离**前端使用Vue.js后端使用FastAPI提高开发效率和系统性能
3. **多端支持**支持Web控制台和Pad控制端满足不同场景的使用需求
4. **AI能力集成**集成了人脸识别、智能对话和搜索增强等AI能力提升系统智能化水平
5. **丰富的外部接口**:与门禁系统、机器人硬件等多种外部设备和服务进行集成
6. **完善的权限管理**:支持基于角色的权限控制,确保系统安全
7. **实时监控与统计**:提供系统统计和识别记录管理,便于数据分析和决策
## 7. 系统部署架构
```mermaid
flowchart TD
subgraph 服务器集群
LoadBalancer["负载均衡器\n(Nginx)"]
Backend1["FastAPI节点1"]
Backend2["FastAPI节点2"]
Backend3["FastAPI节点3"]
end
subgraph 数据层
DB[("主数据库\n(MySQL/PostgreSQL)")]
DB2[("从数据库\n(MySQL/PostgreSQL)")]
RedisCluster["Redis集群\n(主从架构)"]
end
subgraph 外部服务
RAGFlow["RAGFlow服务"]
Compreface["Compreface服务"]
HaiKang["海康平台"]
end
用户["用户"] -->|HTTP请求| LoadBalancer
LoadBalancer -->|分发请求| Backend1
LoadBalancer -->|分发请求| Backend2
LoadBalancer -->|分发请求| Backend3
Backend1 -->|读写| DB
Backend2 -->|读写| DB
Backend3 -->|读写| DB
DB -->|同步| DB2
Backend1 -->|缓存操作| RedisCluster
Backend2 -->|缓存操作| RedisCluster
Backend3 -->|缓存操作| RedisCluster
Backend1 -->|API调用| RAGFlow
Backend2 -->|API调用| RAGFlow
Backend3 -->|API调用| RAGFlow
Backend1 -->|API调用| Compreface
Backend2 -->|API调用| Compreface
Backend3 -->|API调用| Compreface
Backend1 -->|API调用| HaiKang
Backend2 -->|API调用| HaiKang
Backend3 -->|API调用| HaiKang
```
## 8. 系统扩展性设计
1. **微服务架构支持**:系统可扩展为微服务架构,将不同功能模块拆分为独立服务
2. **插件化设计**:支持通过插件方式扩展系统功能
3. **API网关集成**可集成API网关统一管理API访问
4. **容器化部署**支持Docker容器化部署便于水平扩展
5. **云原生支持**支持在Kubernetes等容器编排平台上部署
## 9. 系统安全设计
1. **身份认证与授权**采用JWT令牌机制支持基于角色的访问控制
2. **数据加密**敏感数据加密存储传输过程使用HTTPS
3. **接口安全**所有API接口均需认证部分接口需额外权限验证
4. **日志审计**:记录所有用户操作和系统事件,便于审计和追踪
5. **防SQL注入**使用ORM框架和参数化查询防止SQL注入攻击
6. **防XSS攻击**:对输入输出进行过滤,防止跨站脚本攻击
## 10. 总结
康达机器人系统采用现代化的技术架构集成了多种AI能力和外部服务为用户提供全面的机器人管理和控制解决方案。系统具有良好的扩展性、安全性和可维护性能够满足不同规模和场景的使用需求。

View File

@ -1,587 +0,0 @@
一、公司概况类
1.康达新材料(集团)股份有限公司成立于哪一年?
•答案1988年
2.康达新材料(集团)股份有限公司的上市时间是什么时候?
•答案2012年4月
3.康达新材料(集团)股份有限公司的股票代码是什么?
•答案002669.SZ
4.康达新材的实际控制人是谁?
•答案:唐山市人民政府国有资产监督管理委员会
5.康达新材的股权背景链条是怎样的?
•答案:唐山市人民政府国有资产监督管理委员会→唐山控股发展集团股份有限公司→唐山工业控股集团有限公司→康达新材料(集团)股份有限公司
6.康达新材的三大业务板块是什么?
•答案:胶粘剂与特种树脂新材料、电子信息材料和电子科技
7.康达新材的业务范围覆盖哪些新兴产业?
•答案:装备制造、新能源、轨道交通、航空航天、电子信息及低碳环保等新兴产业
8.截至2024年底康达新材的总资产是多少
•答案69.40亿元
9.康达新材2024年的营业收入是多少
•答案31亿元
10.截至2024年底康达新材的员工总人数有多少
•答案1637人
11.康达新材的管理总部位于哪里?
•答案:浦东新区张江科学城
12.康达新材在国内哪些地区设有子公司、生产基地或分支机构?
•答案:上海、北京、天津、深圳、大连、成都、香港、福建、唐山等地
13.康达新材的海外布局有多少处?
•答案3处
14.康达新材有多少个生产基地?
•答案7个
15.康达新材的胶粘剂产品牌号数有多少?
•答案500+
16.康达新材在多个细分领域的市场地位如何?
•答案:多项细分领域市场地位第一
17.康达新材的使命是什么?
•答案:服务国家战略,引领行业发展
18.康达新材的愿景是什么?
•答案:成为具有全球化视野的“新材料+电子科技”集团化企业
19.康达新材的核心价值观是什么?
•答案:融合、协同、创新、超越
20.康达新材的企业作风是什么?
•答案:不断学习,立即行动,没有任何借口
21.康达新材的发展战略核心是什么?
•答案:坚守“稳中求进”工作总基调,以科技创新为根本动力,以转型升级、抢占新赛道为基本路径,以高质量发展为主题,立足主业,打造“新材料+电子科技”国家级“专精特新”小巨人企业集群
22.康达新材“1+2+3+1+N”战略布局中的“1个产业研究院”具体定位是什么
•答案:产业发展智库,科技成果研发、转化合作平台,技术信息共享中心
23.康达新材“1+2+3+1+N”战略布局中的“2个战略新兴产业方向”是什么
•答案:新材料+电子科技
24.康达新材“1+2+3+1+N”战略布局中的“3大业务板块”具体指什么
•答案:胶粘剂与特种树脂新材料+电子信息材料+电子科技
25.康达新材“1+2+3+1+N”战略布局中的“1+N个产业园基地”已在哪些地区建立
•答案:上海、北京、成都、天津、大连、深圳、唐山、福建邵武、香港、泰国等地
26.康达新材在新材料领域的进口替代目标涉及哪些领域?
•答案:半导体材料、显示材料、生物医用材料、新能源材料、高性能纤维、高性能膜材料、先进高分子材料及其他领域
27.康达新材在半导体材料领域的进口依赖材料有哪些?
•答案大尺寸硅材料、大尺寸碳化硅单晶、SOI、高饱和度光刻胶、高性能靶材、电子特种气体、湿电子化学品、氮化镓单晶/氮化镓单晶衬底、化学机械抛光CMP材料、封装基板、高密度陶瓷材料等
28.康达新材在显示材料领域的进口依赖材料有哪些?
•答案OLED发光材料、超薄玻璃、高世代线玻璃基板、精细金属掩模板FMM、光学膜、柔性PI膜、偏光片、高性能水汽阻隔膜、异方性导电胶膜ACF、特种光学聚氨酯膜PET、OCA光学胶、微球、抗指纹涂层AFC涂料等
29.康达新材在生物医用材料领域的进口依赖材料有哪些?
•答案:医用级钛粉与镍钛合金粉、苯乙烯类热塑性弹性体、医用级聚乳酸、碲锌镉晶体、人工晶状体等
30.康达新材在新能源材料领域的进口依赖材料有哪些?
•答案:硅碳负极材料、电解铜箔、电解液添加剂、铝塑膜、质子交换膜、氢燃料电池催化剂、气体扩散层材料等
31.康达新材在高性能纤维领域的进口依赖材料有哪些?
•答案:高性能碳纤维及其复合材料、高性能对位芳纶纤维及其复合材料、超高分子量聚乙烯纤维等
32.康达新材在高性能膜材料领域的进口依赖材料有哪些?
•答案:海水淡化反渗透膜、陶瓷膜、离子交换膜、中空纤维膜、高导热石墨膜等
33.康达新材在先进高分子材料领域的进口依赖材料有哪些?
•答案聚苯硫醚PPS、聚砜PSF、聚醚醚酮PEEK、聚偏氯乙烯PVDF、聚甲醛POM、有机硅等
34.康达新材在“其他”领域的进口依赖材料有哪些?
•答案高频覆铜板基材、液晶高分子聚合物LCP
35.康达新材及下属子公司中获得国家级“专精特新”小巨人企业认定的有哪些?
•答案大连齐化新材料有限公司有效期2022年7月1日至2025年6月30日、成都必控科技有限责任公司、上海晶材新材料科技有限公司、康达新材料(集团)股份有限公司
36.北京力源兴达科技有限公司获得了什么级别的“专精特新”相关认定?
•答案:北京市专精特新“小巨人”及中小企业
37.成都赛英科技有限公司获得了什么级别的“专精特新”相关认定?有效期是多久?
•答案四川省专精特新中小企业有效期为2022年11月1日-2025年10月31日
38.上海理日新材料科技有限公司获得了什么级别的“专精特新”相关认定?
•答案:上海市专精特新中小企业
39.大连齐化获得了哪些资质认证?
•答案2020年12月被科技部火炬中心认定为国家级“高新技术企业”被辽宁省科技厅认定为“雏鹰企业”2023年5月质检中心被中国石油和化学工业联合会认定为“A级”石油和化工企业质量检验机构通过ISO9001、ISO14001、ISO45001三体系认证
40.河北惟新科技有限公司获得了什么资质?认定编号和有效期是多少?
•答案河北省科技型中小企业认定编号K23016712有效期3年
二、历史发展类
1.康达新材在1988年发生了什么关键事件
•答案:成立上海康达化工实验厂
2.康达新材在2000年发生了什么关键事件
•答案:成立上海康达化工技术研究所
3.康达新材在2002年完成了哪两项重要事件
•答案引入战略投资者完成股份制改革整体变更设立为上海康达化工新材料股份有限公司获得中国合格评定国家认可委员会CNAS认可的实验室资质
4.康达新材在2008年发生了什么关键事件
•答案:成立上海康达化工有限责任公司;被认定为国家高新技术企业
5.康达新材在2012年发生了什么关键事件
•答案:成功在深圳交易所上市
6.康达新材在2016年发生了什么关键事件
•答案非公开发行股票融资8.5亿元,助推康达新材高质量发展
7.2018年康达新材收购了成都赛英科技有限公司,此次收购的目的是什么?
•答案:完善电子科技领域产业链布局
8.2018年康达新材收购了上海晶材新材料科技有限公司,此次收购的目的是什么?
•答案:布局先进陶瓷新材料领域,打造“专精特新”小巨人企业集群
9.2018年康达新材收购了大连齐化新材料有限公司,此次收购的目的是什么?
•答案:向产业链上游战略延伸,打造环氧树脂产业闭环“生态圈”
10.2019年康达新材收购了成都必控科技有限责任公司,此次收购的意义是什么?
•答案:成功迈入电子科技领域
11.康达新材的研发中心被认定为国家企业技术中心是在哪一年?
•答案2019年
12.康达新材的控股股东变更为唐山工业控股集团有限公司是在哪一年?
•答案2019年
13.康达新材更名为“康达新材料(集团)股份有限公司”是在什么时间?
•答案2021年
14.康达新材在2021年进行集团化战略布局的范围是什么
•答案:全国区域
15.康达新材被认定为国家级“专精特新”小巨人企业是在哪一年?
•答案2021年
16.2022年康达新材收购了西安彩晶光电科技股份有限公司,此次收购进入了哪些领域?
•答案:电子信息材料、新能源材料、医药领域,打造新材料“第二增长极”
17.康达新材收购河北惟新科技有限公司是在哪一年?
•答案2023年
18.康达新材收购河北惟新科技有限公司解决了什么“卡脖子”问题?
•答案大尺寸ITO靶材“卡脖子”问题
三、生产基地与研发中心类
1.奉贤研发及生产基地(上海)的位置在哪里?
•答案:上海奉贤杭州湾经济技术开发区
2.奉贤研发及生产基地(上海)的占地面积是多少?
•答案205亩
3.奉贤研发及生产基地(上海)的建设历程是怎样的?
•答案包含一期、二期、三期项目2009年一期建成投产2015年二期建成投产2019年三期建成投产
4.奉贤研发及生产基地(上海)的定位是什么?
•答案:遵循高端化、数字化、一体化、绿色生态的发展理念,打造胶粘剂、复合材料等新材料产业链;奉贤基地二期全面启用后,形成集科研开发、生产、服务、贸易为一体的科研产业综合实体
5.奉贤研发及生产基地(上海)的胶粘剂产品产能是多少?
•答案环氧结构胶、环氧基体树脂、丙烯酸胶、聚氨酯胶、丁基胶等胶粘剂产品产能80000吨
6.奉贤研发及生产基地(上海)的复合材料产能是多少?
•答案环氧基、聚氨酯基复合材料10000吨
7.唐山丰南生产基地(河北)的位置在哪里?
•答案:河北省唐山市丰南经济开发区化工产业园区
8.唐山丰南生产基地(河北)的占地面积是多少?
•答案114亩
9.唐山丰南生产基地(河北)的主要产品有哪些?
•答案:水性聚氨酯丙烯酸酯分散体、无溶剂复膜胶、改性型溶剂聚氨酯复膜胶、改性橡胶树脂溶剂胶、高性能丙烯酸酯结构胶、硅胶、环氧树脂胶
10.唐山丰南生产基地(河北)辐射哪些市场?
•答案:北方市场
11.唐山丰南生产基地(河北)的产品应用于哪些领域?
•答案:风电叶片制造、包装材料、轨道交通、汽车、电子电器、机械设备、建筑等领域(含在建基地)
12.福建邵武生产基地的位置在哪里?
•答案:福建省邵武市金塘省级化工园区
13.福建邵武生产基地的占地面积是多少?
•答案95亩
14.福建邵武生产基地的主要产品有哪些?
•答案:功能型复膜胶、改性弹性树脂胶黏剂、高性能结构胶、功能性聚酯及反应型热熔胶、特种树脂中间体
15.福建邵武生产基地辐射哪些市场?
•答案:南方市场
16.福建邵武生产基地的产品应用于哪些领域?
•答案:包装材料、电子电器、机械设备、建筑装饰及工业维修等领域
17.福建邵武生产基地的战略意义是什么?
•答案:为核心产品提供重要原材料(含在建基地)
18.大连齐化产业园区的位置在哪里?
•答案:辽宁省大连经济技术开发区
19.大连齐化产业园区的主要产品系列有哪些?
•答案双酚A型环氧树脂、耐热型环氧树脂和特种环氧树脂三大系列
20.大连齐化产业园区的具体产品包含哪些?
•答案双酚A型液体环氧树脂、双酚A型固体环氧树脂、溴化环氧树脂、邻甲酚醛环氧树脂、苯酚酚醛环氧树脂、双酚F型环氧树脂、苯氧基树脂、环氧固化剂、环氧稀释剂等多个品种
21.大连齐化产业园区液态环氧树脂的装置数量、产能和实际产能分别是多少?
•答案装置数量1套产能3.4万吨实际产能4.3万吨
22.大连齐化产业园区固态环氧树脂的装置数量、产能和实际产能分别是多少?
•答案装置数量1套产能0.5万吨实际产能1.5万吨
23.大连齐化产业园区邻甲酚醛环氧树脂的装置数量和产能分别是多少?
•答案装置数量1套产能0.5万吨
24.大连齐化产业园区特种树脂中试装置的数量和产能分别是多少?
•答案装置数量1套产能1000吨
25.大连齐化产业园区的战略定位是什么?
•答案:重点布局下游产业链,打造环氧树脂产业闭环“生态圈”,以大连齐化的低溴环氧树脂技术为依托,开展覆铜板领域的战略布局
26.成都康达电子科技产业园的位置在哪里?
•答案:四川省成都市高新区未来科技城
27.成都康达电子科技产业园的占地面积是多少?
•答案64亩
28.成都康达电子科技产业园的定位是什么?
•答案:打造电子科技领域系统级产品研发、生产科技创新园区,使之成为四川乃至西南地区具有比较优势的电子信息特色产业园,推动地方战略性新兴产业的发展,助力公司电子科技核心业务做强做精
29.康达新材的胶粘剂研发中心拥有哪些资质平台?
•答案国家级的企业技术中心、上海胶粘剂工程技术研究中心、上海市企业技术中心、企业博士后科研工作总站、国家认定博士后科研工作站人力资源和社会保障部、全国博士后管委会制发、国家认可委认可的CNAS国家实验室、德国劳氏船级社GL中国认可检测中心
30.康达新材胶粘剂研发中心的技术型研发占比多少?主要内容是什么?
•答案占比25%,主要内容是引进项目的消化、吸收
31.康达新材胶粘剂研发中心的产品型研发占比多少?主要内容是什么?
•答案占比50%,主要内容是现有产品的再创新;中试生产及工艺优化
32.康达新材胶粘剂研发中心的关键技术研发占比多少?主要内容是什么?
•答案占比20%,主要内容是关键原材料及高端技术研发,为产品持续的市场竞争力提供支持
33.康达新材胶粘剂研发中心的技术服务型研发占比多少?主要内容是什么?
•答案占比5%,主要内容是与目前的板块服务相对应
四、财务数据类
1.康达新材2021年的营业收入是多少
•答案27.93亿元
2.康达新材2021年归属于上市公司股东的净利润是多少
•答案:-2.46亿元
3.康达新材2023年的营业收入是多少
•答案8.77亿元
4.康达新材2023年归属于上市公司股东的净利润是多少
•答案0.06亿元
5.康达新材2024年的营业收入是多少
•答案31.01亿元
6.康达新材2024年归属于上市公司股东的净利润是多少
•答案0.30亿元
7.2022年康达新材的研发人员数量是多少?
•答案376人
8.2023年康达新材的研发人员数量是多少?
•答案378人
9.2024年康达新材的研发人员数量是多少?
•答案486人
10.2022-2024年康达新材的研发人员数量呈现什么趋势
•答案:呈线性增长趋势
11.2022年康达新材的研发费用是多少?
•答案1.26亿元
12.2023年康达新材的研发费用是多少?
•答案1.78亿元
13.2024年康达新材的研发费用是多少?
•答案2.04亿元
14.2022-2024年康达新材的研发费用呈现什么趋势
•答案:呈线性增长趋势
15.2024年康达新材的研发人员数量占比是多少?
•答案22.97%
16.2024年康达新材的非研发人员占比是多少?
•答案77.03%
17.2024年康达新材的研发支出占营业收入总额的比例是多少?
•答案6.56%
18.2024年康达新材的非研发支出占比是多少?
•答案93.44%
19.康达新材2021年的总资产是多少
•答案37.28亿元
20.康达新材2022年的总资产是多少
•答案53.33亿元
21.康达新材2023年的总资产是多少
•答案69.40亿元
22.康达新材2024年的总资产是多少
•答案71.23亿元
23.康达新材2021年的净资产是多少
•答案22.91亿元
24.康达新材2022年的净资产是多少
•答案29.06亿元
25.康达新材2023年的净资产是多少
•答案31.43亿元
26.康达新材2024年的净资产是多少
•答案33.09亿元
五、业务介绍类
(一)胶粘剂与特种树脂新材料
1.康达新材的胶粘剂与特种树脂新材料业务国内布局包含哪些企业?
•答案:河北惟新科技、北京康达晟珊、北京力源兴达、唐山南区康达化工新材有限公司、康达国际供应链(天津)有限公司、大连齐化新材、上海康达新材料科技有限公司、上海理日新材、上海晶材科技、福建南平天宇、成都必控科技、福建康达鑫宇新材料有限公司、成都赛英科技、深圳康达电子材料研发有限公司、上海康达新材(香港)有限公司
2.康达新材的胶粘剂与特种树脂新材料业务海外研发办事处设在哪些国家?
•答案:德国、日本
3.康达新材的胶粘剂与特种树脂新材料业务海外营销办事处设在哪个国家?
•答案:印尼
4.康达新材的胶粘剂与特种树脂新材料业务海外生产基地设在何处?
•答案:泰国曼谷
5.康达新材的胶粘剂与特种树脂新材料业务海外覆盖哪些区域?
•答案:德国、丹麦、西班牙、日本、东南亚、巴西等
6.胶粘剂与特种树脂新材料业务的产品体系包含多少大系列?
•答案8大产品系列
7.胶粘剂与特种树脂新材料业务的产品体系包含多少种规格型号?
•答案500多种
8.胶粘剂与特种树脂新材料业务的核心应用领域有哪些?
•答案:风力发电、光伏太阳能、轨道交通、航空航天、海洋船舶工程、软包装复合、橡塑制品、建筑工程、电子电器、汽摩配件、电机电梯、矿业设备、工业维修、新能源汽车、工程维护、高端制造等
9.康达新材在风电领域的核心产品有哪些?
•答案:风电胶粘剂系列产品(结构胶、灌注树脂、胶条、喷胶)
10.2024年康达新材风电领域的销售量是多少?
•答案近9万吨
11.2024年康达新材风电领域的销售额(不含税)是多少?
•答案约16亿元
12.康达新材风电领域的客户覆盖范围是什么?
•答案:国内所有叶片厂商及其基地,同时产品向海外市场推广
13.康达新材风电领域的核心客户有哪些?
•答案三一重能、中国中材、中国国电、艾郎科技、中科宇能、远景能源、金风科技、时代新材、上玻院、双瑞风电、上海电气、天顺风能、LM艾尔姆、明阳电气、MENS Gamesa等
14.康达新材在风电领域的市场地位如何?
•答案:市场占有率第一,自主产品保持品牌技术领先、行业领导地位
15.康达新材在复膜胶领域的市场份额是多少?
•答案25%
16.复膜胶领域中,法国波士胶的市场份额是多少?
•答案25%
17.复膜胶领域中,德国汉高的市场份额是多少?
•答案20%
18.复膜胶领域中其他30余家企业的市场份额总和是多少
•答案30%
19.康达新材在复膜胶领域的市场地位如何?
•答案:市场占有率第一
20.2024年康达新材复膜胶领域的国内客户数量是多少?
•答案700家
21.2024年康达新材复膜胶领域的销售额是多少?
•答案约3.2亿元
22.康达新材复膜胶领域的销售额年增长率是多少?
•答案10-15%
23.康达新材复膜胶领域的软包装复合胶包含哪些类型?
•答案:溶剂型聚氨酯复膜胶、无溶剂聚氨酯复膜胶
24.康达新材复膜胶领域的硬包装胶包含哪些类型?
•答案:外包装热熔胶、标签快递单压敏胶等
25.康达新材复膜胶领域的能量固化印刷油墨包含哪些类型?
•答案UV胶印油墨、UV柔版光油等
26.康达新材复膜胶领域的可降解材料包含哪些类型?
•答案:酪蛋白标签胶、环保餐具涂层
27.康达新材复膜胶领域的发展规划有哪些?
•答案传统替代、新品攻关UV油墨、可降解材料、专业化服务、节能环保、对接“一带一路”
28.康达新材在轨道交通领域的核心产品有哪些?
•答案双组份丙烯酸酯结构胶、单组份结构胶、UV胶、PUR、双组份环氧胶、单组份环氧胶、瞬干胶等系列化产品可根据客户需求个性化调整
29.康达新材轨道交通领域重点布局哪些行业?
•答案:消费电子产品组装行业、微型扬声器行业、安防行业、动力电池行业
30.康达新材轨道交通领域在消费电子行业的核心客户有哪些?
•答案:联想、华硕、罗技、韶音
31.康达新材轨道交通领域的产品在消费电子行业应用于哪些产品组装?
•答案:智能手机、笔记本/平板电脑、穿戴设备、无人机、投影仪组装
32.康达新材轨道交通领域在微型扬声器行业的核心客户有哪些?
•答案:瑞声、歌尔、豪声、上声
33.康达新材轨道交通领域在安防行业的核心客户有哪些?
•答案:海康威视、大华
34.康达新材轨道交通领域针对高铁/地铁的产品有哪些?
•答案:地板胶、阻尼浆、阻尼贴片
35.康达新材轨道交通领域针对高铁/地铁的产品取得了哪些进展?
•答案:阻尼贴片材料通过中车系统检测验证,地板胶阻尼浆在中车系统重点客户试装成功
36.康达新材通用工业领域的销售渠道以什么为主?
•答案:经销商销售渠道
37.康达新材通用工业领域重点覆盖哪些市场?
•答案通用工业工业装配维修、扬声器、电梯、电机、结构胶等各类工业应用、流通市场民用及家装DIY、电商
38.康达新材的汽车胶粘剂用于哪些场景?
•答案:汽车厢体、车门的结构粘接及汽车内饰件粘接
39.康达新材的汽车胶粘剂能为客户提供什么优化方案?
•答案汽车轻量化和减少VOCs排放的优化方案
40.康达新材家电用胶粘剂的既定目标客户有哪些?
•答案:格力、美的等国内知名家电企业
41.康达新材家电用胶粘剂目前已涉及美的哪些产品应用?
•答案:美的厨热、冰箱和家用空调等产品
42.康达新材家电用胶粘剂未来的拓展计划是什么?
•答案:拓展至中央空调、洗衣机等其他生活电器
(二)核心子公司业务详情(胶粘剂与特种树脂新材料板块)
1.大连齐化新材料有限公司的成立时间是什么时候?
•答案起步于2001年
2.大连齐化新材料有限公司的企业定位是什么?
•答案:以生产销售高品质环氧树脂为主,集新材料研制、开发、生产、销售、服务、转让为一体的综合性高新技术化工企业
3.大连齐化新材料有限公司的产品体系包含哪些系列?
•答案双酚A型环氧树脂、耐热型环氧树脂和特种环氧树脂三大系列
4.大连齐化新材料有限公司的具体产品有哪些?
•答案双酚A型液体环氧树脂、双酚A型固体环氧树脂、溴化环氧树脂、邻甲酚醛环氧树脂、苯酚酚醛环氧树脂、双酚F型环氧树脂、苯氧基树脂、环氧固化剂、环氧稀释剂等
5.大连齐化新材料有限公司的产品质量指标有什么优势?
•答案各项指标均优于中国国家标准GB/T 13657-2011《双酚A型环氧树脂》通过RoSH和REACH认证双酚A型环氧树脂被辽宁省工信厅认定为“专精特新”产品并获欧洲化学品管理局ECHA“REACH注册证书”
6.大连齐化新材料有限公司拥有多少项实用新型专利?
•答案21项
7.大连齐化新材料有限公司拥有多少项软件著作权?
•答案20项
8.大连齐化新材料有限公司正在申请多少项发明专利?
•答案2项
9.大连齐化新材料有限公司通过了哪些体系认证?
•答案ISO9001、ISO14001、ISO45001三体系认证
10.大连齐化新材料有限公司获得国家级“高新技术企业”认定的时间是什么时候?
•答案2020年12月
11.大连齐化新材料有限公司获得辽宁省科技厅“雏鹰企业”认定的时间是什么时候?
•答案2020年12月
12.大连齐化新材料有限公司获得国家级“专精特新”小巨人企业认定的时间是什么时候?
•答案2021年7月
13.大连齐化新材料有限公司的销售模式是什么?
•答案:直销模式
14.南平天宇实业被康达新材收购的时间是什么时候?
•答案2021年4月
15.南平天宇实业的占地面积是多少?
•答案33000㎡
16.南平天宇实业的年产产值是多少?
•答案近6000万元
17.南平天宇实业的生产工艺技术水平如何?
•答案:国际领先水平
18.南平天宇实业的产品定位是什么?
•答案:亚洲国家“水性商标胶粘剂”生产量最大、生产品种最多、工艺技术最领先的绿色环保水基性商标胶粘剂生产企业
19.南平天宇实业的“远洋牌”水性系列商标胶有什么特点?
•答案:质量超越国际领先水平,性能稳定
20.南平天宇实业的“远洋牌”封箱专用热熔胶有什么特点?
•答案:可塑性粘合剂,无毒、无味,属绿色环保型产品,物理状态随温度改变(化学特性不变)
21.南平天宇实业的“远洋牌”水性纸制品胶粘剂的原材料是什么?
•答案优质高分子材料PVA、VAC、改性淀粉共聚合成
22.南平天宇实业的“远洋牌”水性纸制品胶粘剂有什么特点?
•答案:无毒性、无公害、无腐蚀性及氧化性,符合欧美最新标准,为食品级纸制品行业不可替代的绿色环保产品
23.南平天宇实业的核心客户有哪些?
•答案:百威啤酒、珠江啤酒、青岛啤酒、雪花啤酒、达利食品集团等
24.上海理日新材料的技术地位如何?
•答案:成熟的研发创新能力,技术和产品保持国内领先、国际先进水平,国内市场品牌影响和占有率仅次于德国汉高等顶级跨国公司,产品已通过多家著名跨国公司认证并供货
25.上海理日新材料的应用领域有哪些?
•答案:汽车部件、电子电缆、衣饰、制鞋、建材、装饰、包装以及低压注塑等行业
26.上海理日新材料服务多少家客户?
•答案:数百家
27.上海理日新材料的环保型高性能热熔胶包含哪些类型?
•答案:聚酯、聚酰胺热熔胶
28.上海理日新材料的环保型高性能热熔胶有什么特点?
•答案:不含化学溶剂、无污染,粘接强度高,耐油耐化学性好,粘接材料广泛
29.上海理日新材料的环保型高性能热熔胶应用于哪些企业?
•答案:汽车滤清器生产企业、制鞋服饰企业、电子电缆生产企业
30.上海理日新材料的环保型低压注塑封装材料的目标市场是什么?
•答案:电缆电子行业中的电池板生产企业、线束插头/微型开关生产企业、连接器/传感器生产企业和PCB线路板生产企业
31.四氢呋喃可作为上海理日新材料产品的哪些应用领域?
•答案:合成树脂的工业溶剂、合成革的表面处理剂、合成农药等领域
(三)高性能复合材料方向
1.康达新材在高性能复合材料方向的战略定位是什么?
•答案聚焦玻璃纤维、碳纤维的环氧树脂、聚氨酯类复合材料领域计划通过2-3年深化拓展基于自身工艺和技术积累通过投资业务契合度企业、技术创新、加大研发投入等方式切入先进复合材料领域推动向高分子新材料领域战略转型
2.康达新材落实先进复合材料转型战略的关键举措是什么?
•答案:对聚发新材进行增资
3.拉挤树脂Urepul的基础材料是什么
•答案:玻纤&碳纤
4.拉挤树脂Urepul的应用领域有哪些
•答案:桥架、绝缘梯、桥梁、高压管道、景观工程、高铁、轨道、光伏
5.SMC/预浸料Urepreg的基础材料是什么
•答案:玻纤&碳纤
6.SMC/预浸料Urepreg的应用领域有哪些
•答案:汽车、轨道交通、电子产品
7.RTM树脂Urethan的基础材料是什么
•答案:玻纤&碳纤
8.RTM树脂Urethan的应用领域有哪些
•答案:风电叶片、汽车内外饰、高铁
9.缠绕树脂Urecom的基础材料是什么
•答案:玻纤&碳纤
10.缠绕树脂Urecom的应用领域有哪些
•答案:电线杆、传动轴
11.截至2025年8月康达新材高性能复合材料已实现量产应用的产品有哪些
•答案:电缆桥架、高铁设备舱及裙板、新能源车电池盒骨架
12.截至2025年8月康达新材高性能复合材料技术开发完成的产品有哪些
•答案:汽车型材、托盘、高铁步道板、绝缘臂腕
13.截至2025年8月康达新材高性能复合材料处于开发中的产品有哪些
•答案:太阳能边框及支架、铁路鱼尾板
14.康达新材的高性能复合材料在性能方面有什么优势?
•答案:出色的机械性能,与玻纤完美结合,更高的粘接强度,优异的抗疲劳性能
15.康达新材的高性能复合材料在生产效率方面有什么优势?
•答案:更快的灌注速度,更快的固化速度
16.康达新材的高性能复合材料在综合成本方面有什么优势?
•答案:模具投入少,具有竞争力的树脂价格
(四)电子信息材料
1.惟新科技被康达新材收购的时间是什么时候?
•答案2023年
2.惟新科技的企业定位是什么?
•答案国家高新技术企业致力于研发和生产高端ITO氧化铟锡靶材及ITO粉体、ITO气氛烧结炉等ITO周边产品解决大尺寸ITO靶材“卡脖子”问题
3.惟新科技的核心技术有哪些?
•答案与清华大学化工系合作研发微反应器制备高活性纳米ITO粉体技术自主研发适合超大尺寸靶材制备的湿法注浆成型技术拥有自主知识产权的超大空间高温烧结炉
4.惟新科技成功制备的大尺寸ITO靶材规格是多少
•答案1550x250mm
5.惟新科技制备的大尺寸ITO靶材性能指标如何
•答案:与国际同类靶材相当,达到国际先进水平,填补国内空白
6.惟新科技的战略意义有哪些?
•答案打破技术壁垒减少高端靶材进口依赖助力中美贸易战应对推动我国铟资源高效利用填补我国ITO靶材在中、高端平板显示器制造领域应用空白促进ITO靶材平板生产工艺研发与人才培养
7.惟新科技的ITO靶材试验线设备升级改造完成时间是什么时候
•答案2022年
8.惟新科技目前的产能提升目标是什么?
•答案推进30T/年产能提升工作
9.惟新科技的溅射靶材下游覆盖哪些领域?
•答案:平板显示器、光伏电池、记录媒体、半导体等领域
10.平板显示器领域在惟新科技溅射靶材下游应用中占比多少?
•答案33.8%
11.记录媒体领域在惟新科技溅射靶材下游应用中占比多少?
•答案28.6%
12.半导体领域在惟新科技溅射靶材下游应用中占比多少?
•答案18.5%
13.晶材科技成立于哪一年?
•答案2016年
14.晶材科技被康达新材收购的时间是什么时候?
•答案2018年
15.晶材科技的企业定位是什么?
•答案:专注于高端电子陶瓷材料国产化,集研发与规模化生产于一体,提供先进材料解决方案,代理德国瓦克化学有机硅产品
16.晶材科技的技术路线是什么?
•答案:微晶玻璃体系、微晶玻璃/陶瓷复合体系
17.晶材科技在行业中的地位如何?
•答案:目前市场唯一批量供货的国产生料带供应商,解决“卡脖子”难题
18.晶材科技的自研产品有哪些?
•答案:陶瓷生料带、贵金属浆料、瓷粉、导电胶
19.晶材科技的自研产品应用于什么技术领域?
•答案低温共烧陶瓷技术LTCC的电子元器件、电路模块制造和封装
20.晶材科技的代理产品是什么?
•答案:有机硅水胶(车载显示器光学全贴合重要原材料)
21.晶材科技的产品在军用领域有什么应用?
•答案:有源相控阵雷达
22.晶材科技的产品在民用领域有什么应用?
•答案高端半导体传感器、光通信器件、汽车电子电路模块、5G路由器、5G机房、数据中心等
23.晶材科技的生料带现有产能是多少?
•答案240万片/年
24.晶材科技的贵金属浆料现有产能是多少?
•答案30吨/年
(五)电子科技——赛英科技
1.赛英科技被康达新材收购的时间是什么时候?
•答案2018年
2.赛英科技的地理位置在哪里?
•答案:成都龙潭新经济产业功能区
3.赛英科技的科研生产基地规模是多少?
•答案8000余平方米
4.赛英科技的核心业务是什么?
•答案:科研、生产整机雷达、微波组件、专用仪器仪表、海洋通讯产品
5.赛英科技在安全管控领域的产品有哪些?
•答案:近程警戒雷达(地面、海面)、周界安全警戒雷达(系列产品)
6.赛英科技在交通监测领域的产品有哪些?
•答案FOD跑道异物监测雷达塔架、移动
7.赛英科技在工业监测领域的产品有哪些?
•答案:高炉料面监测雷达、微位移监测雷达(应用于大型钢厂、铁路大坝等重要区域)
8.赛英科技获得了哪些企业荣誉?
•答案成都市企业技术中心、成都市成华区2020年度“工业纳税先进单位”、四川省“专精特新”中小企业、成都市科技装备业商会“副会长单位”等
六、康达新材日常聊天类
1你能给康达新材创作一首诗吗
•答案:匠心三十载耕耘,新材科技破卡颈胶黏万物兴百业,引领制造向前行
2如果用三个关键词概括康达新材的核心气质你觉得会是什么为什么
•答案:硬核(深耕“卡脖子”技术)、创新(研发投入持续增长)、多元(覆盖多业务板块)
3假设你要给朋友介绍康达新材会用一段轻松有趣的话怎么说
•答案这家1988年成立的国企超牛能做粘风电叶片的“超级胶水”还搞定高端ITO靶材业务横跨新材料和电子科技妥妥的科技实力派
4要是给康达新材设计一句接地气的宣传语不局限于官方口号你会怎么写
•答案:康达新材,粘得牢、造得硬,让中国制造更靠谱!
5想象康达新材要举办一场员工家庭日活动你觉得可以设计哪些有趣的互动环节
•答案①亲子胶粘剂组装模型②VR参观生产基地答题③家庭新材料元素手作赛
6如果你是康达新材的一名新员工入职第一天最想了解公司的哪三个方面
•答案:①岗位与核心业务的关联;②研发创新支持政策;③培训与晋升路径
7用拟人化的手法描述康达新材你会把它比作哪种形象理由是什么
•答案比作“实干工匠”30余年坚守行业身怀多元技能持续突破技术难题
8康达新材涉及多个业务板块要是用一种美食比喻它的业务布局你觉得像什么为什么
•答案:像“什锦火锅”,胶粘剂是锅底,各业务板块是食材,协同发力丰富产业生态
9要是给康达新材的研发人员写一句鼓励的话你会怎么表达
•答案:以匠心攻技术,以创新破壁垒,为中国智造添力!
10假设康达新材要出一款周边产品送给客户你觉得什么类型的产品既实用又能体现公司特色
•答案定制多功能粘接工具套装含迷你环保胶粘剂、ITO靶材图案书签
11用一句话形容康达新材从1988年成立到现在的发展历程你会怎么说
•答案:从化工实验厂到“新材料+电子科技”集团30余年坚守创新领跑细分领域
12如果你要在社交平台分享康达新材的一则动态配文会怎么写才能吸引关注
•答案国企硬核粘风电叶片、破ITO靶材“卡脖子”覆盖新能源、电子科技为中国制造打call#康达新材 #国货之光
13康达新材在多个地区有生产基地要是选一个基地推荐给朋友参观你会选哪个理由是什么
•答案:选上海奉贤基地,集研发生产于一体,能直观看到产品从研发到量产的全过程
14要是给康达新材设计一个吉祥物你觉得它的外形和寓意应该是什么样的
•答案蓝色分子造型小精灵带翅膀象征创新头顶ITO靶材寓意科技赋能
15想象康达新材要拍摄一支企业宣传片你觉得开篇画面应该是什么场景
•答案:高空俯瞰全球生产基地,快速切换研发实验室、生产线、风电应用场景,定格企业口号
16如果你是康达新材的客服接到客户咨询时第一句暖心的开场白会怎么说
•答案:您好!康达新材客服为您服务,有任何产品或合作问题,我都会全力解答~
17用三个 emoji 代表康达新材的业务板块,你会选哪三个?分别对应什么业务?
•答案:🧪(胶粘剂与特种树脂)、💻(电子科技)、📱(电子信息材料)
18康达新材有不少“专精特新”子公司要是给这些子公司办一场表彰会颁奖词可以怎么写
•答案:深耕细分领域,以硬科技破壁垒、填空白,为产业生态注入强劲动力,致敬每一份坚守!
19假设你要给康达新材的员工设计一件文化衫正面和背面会印什么图案或文字
•答案正面康达新材logo+“以新材赋能”;背面:三大业务图标+“融合 协同 创新 超越”
20用简单的语言给小朋友解释康达新材生产的胶粘剂是做什么用的你会怎么说
•答案:这是“超级胶水”,能把风电叶片、汽车零件粘得牢牢的,让它们更结实哦~
21要是康达新材要发起一个公益活动结合它的业务特点你觉得可以开展什么主题的活动
•答案:“绿色新材助环保”,用环保胶粘剂、可降解材料为乡村学校修补课桌椅
22如果你参加康达新材的年会最期待看到哪个环节的表演为什么
•答案:业务板块创意秀,能通过表演直观了解各部门工作,还能感受团队风采
23用对比的方式说说康达新材和你印象中的传统化工企业有什么不同
•答案:传统化工多单一业务、低技术,康达聚焦新兴产业,研发投入高、业务多元且绿色环保
24康达新材的使命是“服务国家战略引领行业发展”要是你是员工会怎么理解这句话并落实到工作中
•答案:紧跟国家需求,研发时聚焦“卡脖子”技术,生产时严把质量关,助力产业升级
25假设你要给康达新材的官网设计一个新栏目你会建议增加什么内容
•答案:“新材科普”栏目,用动画、图文讲解产品原理和应用,开设互动问答
26用一句幽默的话调侃康达新材的“硬核”业务比如胶粘剂、ITO靶材你会怎么说
•答案:康达业务太硬核,万物皆可粘、皆可造,就没有搞不定的技术难题?
27要是康达新材要和一所高校开展合作你觉得可以在哪些领域合作共赢
•答案:①联合研发“卡脖子”技术;②开设定制班培养人才;③加速科研成果转化
28如果你是康达新材的hr招聘时会用什么独特的理由吸引人才加入
•答案:参与热门领域技术攻关,国企保障+清晰晋升,与行业顶尖人才共事
29用比喻的手法说说康达新材的研发团队像什么为什么
•答案:像“产业探路者”,探索前沿技术,开辟新路径,指引产业发展方向
30康达新材海外有布局要是你负责海外业务推广会先给海外客户推荐哪款产品
•答案:风电胶粘剂,市场占有率第一,技术领先,契合全球新能源需求
31假设康达新材要举办一场客户答谢会你觉得现场布置可以融入哪些业务元素
•答案:①产品模型展示区;②分子结构装饰;③产品拼图、技术问答互动
32用一句话总结康达新材对国家新材料产业的意义你会怎么说
•答案:打破进口依赖,树立国产标杆,为新材料产业高质量发展提供支撑
33要是你是康达新材的一名司机开车运送产品时会怎么跟别人介绍车上的货物
•答案:这是国产硬核科技产品,有风电专用胶粘剂、电子设备核心材料,助力多个行业发展~
34康达新材有很多生产基地要是把这些基地比作一串珍珠你觉得哪颗“珍珠”最亮眼
•答案:成都电子科技产业园,聚焦战略新兴产业,是西南地区电子信息特色产业园
35用简单的手势或动作比划康达新材某款产品的用途你会怎么比划
•答案:比划胶粘剂:双手模拟“叶片”,合拢按压示意粘贴牢固
36假设康达新材要出一本企业内刊你会给内刊起什么名字设置哪些栏目
•答案:名字《康达新声》,栏目:总裁寄语、技术前沿、业务动态、员工风采
37用一句话形容康达新材员工的工作状态你会怎么描述
•答案:勤学实干、协同创新,在各自岗位上全力冲刺目标
38要是康达新材要开展员工技能比赛你觉得可以设置哪些比赛项目
•答案:①技术攻关挑战赛;②生产精准操作大赛;③产品推广创意赛
39用对比的方式说说康达新材20年前和现在的变化你会怎么总结
•答案20年前业务单一如今成长为“新材料+电子科技”集团,技术、布局全面升级
40康达新材的核心价值观是“融合、协同、创新、超越”要是你用生活中的例子解释“协同”会选什么例子
•答案:像家庭做饭,分工不同但目标一致,相互配合才能快速做出丰盛饭菜
41假设你要给康达新材的会议室起名字结合业务特色你会起什么名字
•答案:粘合力厅、靶材阁、科创堂、协同馆
42用一句鼓励的话送给正在攻克“卡脖子”技术的康达新材研发团队你会怎么说
•答案:坚守初心攻难关,国产技术定发光,为你们加油!
43要是康达新材要拍一支员工纪录片你觉得应该采访哪些岗位的员工
•答案:研发人员、生产线工人、销售人员、子公司负责人、行政后勤人员
44用比喻的手法说说康达新材的产品像什么比如胶粘剂像“工业胶水”再具体描述一下
•答案①胶粘剂像“工业纽带”连接各类部件②ITO靶材像“电子基石”支撑电子设备运行
45康达新材涉及电子科技领域要是你给长辈解释什么是“微波组件”会怎么说
•答案:这是电子设备的“信号中转站”,能让雷达、通讯设备精准收发信号,保障安全和监测
46假设康达新材要参加一场行业展会你觉得展位设计要突出什么亮点才能吸引观众
•答案突出科技感分子结构造型、LED大屏和互动性产品体验、VR参观
47用一句话说说你对康达新材未来5年发展的期待你会怎么说
•答案:期待成为全球领先的“新材料+电子科技”集团,让更多国产硬核科技走向世界
48要是你是康达新材的食堂阿姨会怎么用食堂菜品比喻公司的业务多元化
•答案:食堂菜像公司业务,有“核心硬菜”(胶粘剂)、“新鲜时蔬”(电子信息材料),搭配均衡、营养丰富~
49用简单的画画形式表现康达新材的业务你会画哪些元素
•答案:画大圆圈代表公司,内部画风电叶片、手机、芯片、分子结构,用箭头连接体现协同
50康达新材有不少荣誉资质要是你把这些荣誉比作公司的“勋章”最想给别人展示哪枚“勋章”为什么
•答案:国家级“专精特新”小巨人企业,体现公司技术实力和细分领域领先地位

View File

@ -1,13 +0,0 @@
### QA问答的修改原则
1. 子问题sub_questions原则
- 子问题的答案必须能在主答案中找到
- 子问题不是对主问题的扩展或深入,而是从主答案中提取的、用户可能问的相关问题
- 如果主答案内容简单(如只有年份、数字等),通常不需要子问题
- 每个问题保留2-3个子问题如果适用
2. 变体variations原则
- 变体是主问题的不同表达方式
- 只保留3个代表性的变体
- 变体应覆盖常见的问法变化(如:去掉疑问词、简化表达、换种说法)

View File

@ -1,58 +0,0 @@
class LoginException(Exception):
"""
自定义登录异常LoginException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message
class AuthException(Exception):
"""
自定义令牌异常AuthException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message
class PermissionException(Exception):
"""
自定义权限异常PermissionException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message
class ServiceException(Exception):
"""
自定义服务异常ServiceException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message
class ServiceWarning(Exception):
"""
自定义服务警告ServiceWarning
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message
class ModelValidatorException(Exception):
"""
自定义模型校验异常ModelValidatorException
"""
def __init__(self, data: str = None, message: str = None):
self.data = data
self.message = message

View File

@ -1,71 +0,0 @@
from fastapi import FastAPI, Request
from fastapi.exceptions import HTTPException
from pydantic_validation_decorator import FieldValidationError
from exceptions.exception import (
AuthException,
LoginException,
ModelValidatorException,
PermissionException,
ServiceException,
ServiceWarning,
)
from utils.log_util import logger
from utils.response_util import jsonable_encoder, JSONResponse, ResponseUtil
def handle_exception(app: FastAPI):
"""
全局异常处理
"""
# 自定义token检验异常
@app.exception_handler(AuthException)
async def auth_exception_handler(request: Request, exc: AuthException):
return ResponseUtil.unauthorized(data=exc.data, msg=exc.message)
# 自定义登录检验异常
@app.exception_handler(LoginException)
async def login_exception_handler(request: Request, exc: LoginException):
return ResponseUtil.failure(data=exc.data, msg=exc.message)
# 自定义模型检验异常
@app.exception_handler(ModelValidatorException)
async def model_validator_exception_handler(request: Request, exc: ModelValidatorException):
logger.warning(exc.message)
return ResponseUtil.failure(data=exc.data, msg=exc.message)
# 自定义字段检验异常
@app.exception_handler(FieldValidationError)
async def field_validation_error_handler(request: Request, exc: FieldValidationError):
logger.warning(exc.message)
return ResponseUtil.failure(msg=exc.message)
# 自定义权限检验异常
@app.exception_handler(PermissionException)
async def permission_exception_handler(request: Request, exc: PermissionException):
return ResponseUtil.forbidden(data=exc.data, msg=exc.message)
# 自定义服务异常
@app.exception_handler(ServiceException)
async def service_exception_handler(request: Request, exc: ServiceException):
logger.error(exc.message)
return ResponseUtil.error(data=exc.data, msg=exc.message)
# 自定义服务警告
@app.exception_handler(ServiceWarning)
async def service_warning_handler(request: Request, exc: ServiceWarning):
logger.warning(exc.message)
return ResponseUtil.failure(data=exc.data, msg=exc.message)
# 处理其他http请求异常
@app.exception_handler(HTTPException)
async def http_exception_handler(request: Request, exc: HTTPException):
return JSONResponse(
content=jsonable_encoder({'code': exc.status_code, 'msg': exc.detail}), status_code=exc.status_code
)
# 处理其他异常
@app.exception_handler(Exception)
async def exception_handler(request: Request, exc: Exception):
logger.exception(exc)
return ResponseUtil.error(msg=str(exc))

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
# 康达新材002669.SZ对外介绍Q&A版
> 本文与《2.0康达新材Q&A清单 251228.md》存在大量重合公司概况/沿革/股权/战略/基地/板块介绍/部分经营与研发数据等。对外统一口径以清单为准。
## 仍保留(本文件独有或更适合对外的补充)
### 1英文名
**A**KangDa New Materials。
### 2对外免责声明/使用说明
**A**如与正式公告/披露存在差异,以公司披露为准。
### 3可选对外呈现的结构建议
**A**对外问答建议直接引用清单中对应条目(公司基本信息→战略→基地→业务板块),避免出现多份口径。

View File

@ -1,11 +0,0 @@
# 康达新材介绍文档250826Q&A版
> 本文内容与《2.0康达新材Q&A清单 251228.md》高度重合公司概况/沿革/股权/战略/基地/业务板块/资质等),对外与对内统一口径以清单为准。
## 仍保留(本文件独有/更适合作为“介绍文档”的补充)
### 1口号
**A**康达匠心赋能 引领制造新材。
### 2原文口径不一致提示用于内部校对
**A**原文个别财务数据在不同位置存在不一致;如需对外口径,请以公司披露/正式财报为准。

View File

@ -1,243 +0,0 @@
# 康达新材2022年年度报告Q&A版
> 说明:本文为对 `md/康达新材2022年年度报告.md` 的要点抽取与问答化重组,便于检索与知识库问答使用;问题为整理者归纳,答案以原文表述与数据为准。
---
## 1. 分配政策
**Q52022年度利润分配现金分红/送股/转增)安排是什么?**
**A** 公司计划不派发现金红利、不送红股、不以公积金转增股本。
---
## 3. 业务板块与产品结构
**Q12公司主要属于哪些行业/业务类型?**
**A** 胶粘剂新材料行业、军工电子科技行业、电子信息材料(含医药中间体与电子化学品等)相关领域。
**Q13公司胶粘剂新材料板块有哪些主要产品应用在哪些领域**
**A** 产品包括环氧树脂胶、聚氨酯胶、丙烯酸酯胶、SBS胶、热熔胶、水性胶等以及环氧/聚氨酯复合材料、聚酰亚胺材料等;应用于风电叶片制造、包装材料、轨道交通、船舶工程、汽车、电子电器、机械设备、建筑装饰、工业维修等。
**Q14胶粘剂业务的经营模式是什么**
**A** “产品+解决方案”。采购以订单与计划为导向、供应商体系管理;生产以销定产并部分常规备货;销售以直销为主,强调技术服务与客户认证。
**Q15军工电子科技板块主要做什么**
**A** 以应用于航空、航天、舰船、兵器等领域的滤波器/滤波组件与电源模块为主要方向,并覆盖电磁兼容相关设备与产品。
**Q16军工电子科技板块的组织架构是什么**
**A** 以晟璟科技为管理平台,下辖必控科技、力源兴达两家全资子公司,并参股成都铭瓷、成都立扬、上海汉未。
**Q17必控科技与力源兴达分别主营什么**
**A** 必控科技:电磁兼容设备/预测试系统/软件与电磁兼容加固产品,含滤波器、滤波组件、电源滤波模块等;力源兴达:电源变换器模块研发设计生产销售,面向军工与电网输配电/工业控制等。
**Q18电子信息材料及医药中间体板块主要包含哪些方向**
**A** 显示材料(液晶混晶/单体/中间体、OLED相关材料、光刻胶感光剂、LCD-PI导向膜单体、ITO靶材等——靶材项目起步阶段暂无规模化销售、医药中间体、新能源电子化学品如电解液添加剂、电子清洗剂
**Q19彩晶光电的业务定位与销售方式有什么特点**
**A** 通过下游认证后按客户材料结构式与指标定制研发与生产,以直销为主;部分日韩地区客户通过指定代理采购商销售。
---
## 5. 2022年经营回顾管理层讨论与分析要点
**Q242022年公司总体经营表现如何**
**A** 营业收入246,636.18万元同比增长8.57%营业利润5,275.40万元同比增长186.13%归母净利润4,791.35万元同比增长117.83%研发投入12,641.94万元占营业收入5.13%期末资产总额53.33亿元同比增长约43.04%归母净资产30.02亿元同比增长32.66%。
**Q25风电叶片制造领域有哪些进展**
**A** 风电胶粘剂保持市占率领先产品成功应用于11款百米级叶片100m126m海外拓展LM Windpower批量采购环氧结构胶、环氧树脂、喷胶等多类型产品。
**Q26软包装无溶剂胶粘剂领域有哪些进展**
**A** 聚氨酯类胶粘剂销售量/额同比稳定增长销售量突破11,000吨覆盖客户超750家国内无溶剂软包装胶粘剂市场占有率领先东南亚/中亚销售网络布局推进;与客户联合申报的相关技术列入《国家清洁生产先进技术目录(2022)》。
**Q27消费电子及家电用胶有哪些进展**
**A** 形成以双组份丙烯酸酯结构胶、单组份结构胶、UV胶、PUR胶、双/单组份环氧胶等为主线的系列化产品近200余个型号与联想、华为、戴尔、华硕、立讯、韶音等合作单组份环氧胶在柔性线路板保护/灌封/密封等领域进入中高端并打破国外垄断电子胶粘剂销售收入稳定增长10%以上。
**Q28军工电子板块有哪些经营与产能/模式探索?**
**A** 必控科技扩充电磁兼容产品型谱探索“多品种、小批量”柔性化Cell-Line生产模式并开始试生产获得四川省“专精特新”中小企业称号力源兴达将民品电源事业部转为军品为重心新增客户23家、新项目45项。
**Q29研发与标准/专利方面有哪些成果?**
**A** 研发费用占营收5.13%新增授权专利16项发明13项、实用新型3项受理发明专利10项参与制定/修订国家标准2项、行业标准1项。
**Q30产能基地建设与项目推进有哪些重点**
**A** 募投项目唐山丰南与福建邵武基地推进天津复材研究中心与军用电源生产基地完成设计并推进审批成都高新区军工电子科技产业园进入规划并签署土地转让协议彩晶光电推进液晶显示材料产业化期二标段项目混合液晶30吨/年、液晶单体40吨/年、液晶中间体250吨/年计划总投资37,350万元预计2023年底主体建设完成
**Q312022年资本运作有哪些关键事项**
**A** 2022年7月15日向特定对象发行股票52,910,052股发行价13.23元/股募集资金总额约7亿元2022年8月收购彩晶光电60.9205%股权,打造“电子信息材料”第二增长极。
**Q32员工激励与股份回购有什么信息**
**A** 报告期内使用自有资金5,430.90万元回购股份并实施第四期员工持股计划授予股份469.14万股。
---
## 6. 主要财务指标(合并口径摘要)
**Q332022/2021/2020营业收入分别是多少**
**A** 2022年2,466,361,756.29元2021年2,271,612,976.74元2020年1,932,135,499.94元。
**Q342022年归母净利润与扣非归母净利润是多少同比如何**
**A** 归母净利润47,913,477.29元(同比+117.83%扣非归母净利润33,756,789.24元(同比+520.23%)。
**Q352022年经营活动现金流净额是多少**
**A** -23,646,854.70元(同比-111.38%)。
**Q362022年基本/稀释每股收益是多少?**
**A** 基本每股收益0.179元/股稀释每股收益0.179元/股。
**Q372022年末总资产与归母净资产是多少**
**A** 总资产5,332,562,034.54元归母净资产3,001,624,183.70元。
**Q382022年加权平均净资产收益率是多少**
**A** 2.10%。
---
## 7. 分季度表现(合并口径)
**Q392022年分季度营业收入分别是多少**
**A** Q1 598,664,229.98元Q2 487,606,208.15元Q3 543,442,867.29元Q4 836,648,450.87元。
**Q402022年分季度归母净利润分别是多少**
**A** Q1 -10,396,127.38元Q2 -4,275,913.77元Q3 -19,085,103.43元Q4 81,670,621.87元。
**Q412022年分季度经营活动现金流净额分别是多少**
**A** Q1 -75,340,459.93元Q2 156,132,079.25元Q3 -21,654,884.68元Q4 -82,783,589.34元。
---
## 8. 非经常性损益
**Q422022年非经常性损益合计是多少主要构成有哪些**
**A** 合计14,156,688.05元。主要包括:政府补助、理财收益/公允价值变动、资产处置损益、其他营业外收支等,并扣除所得税影响与少数股东权益影响。
**Q43“其他符合非经常性损益定义的损益项目”是什么**
**A** 其他权益工具投资持有期间取得的股利收入237,658.95元。
---
## 9. 收入结构与毛利2022年
**Q44按行业看营业收入构成如何**
**A** 胶粘剂15.80亿元64.06%电子产品2.76亿元11.17%复合材料4.32亿元17.53%显示材料0.19亿元0.76%医药中间体0.26亿元1.06%电子化学品0.35亿元1.44%其他业务0.98亿元3.97%)。
**Q45按产品看主要产品收入有哪些**
**A** 环氧胶类9.76亿元聚氨酯胶类2.93亿元轻木套材4.09亿元滤波器及滤波组件1.38亿元电源模块0.93亿元电源滤波模块0.44亿元等。
**Q46胶粘剂/电子产品/复合材料毛利率大致水平如何?**
**A** 胶粘剂毛利率17.74%电子产品毛利率56.04%复合材料毛利率1.69%(报告期披露口径)。
**Q47按销售模式看直销与代销占比如何**
**A** 直销22.08亿元89.52%代销1.61亿元6.51%其他业务0.98亿元3.97%)。
**Q48前五大客户/供应商集中度如何?**
**A** 前五名客户合计销售金额987,551,997.77元占年度销售总额41.70%前五名供应商合计采购金额845,819,887.90元占年度采购总额42.73%。
---
## 10. 费用与研发
**Q492022年主要期间费用是多少同比如何**
**A** 销售费用88,155,461.44元(-6.32%管理费用156,228,970.50元(+14.17%财务费用39,194,908.67元(+50.23%主要因融资额增加研发费用126,419,384.32元(+28.89%)。
**Q50研发人员规模与结构如何**
**A** 研发人员378人同比+32.63%占比24.77%学历结构本科164、硕士57、博士9年龄30岁以下110、3040岁147等。
**Q51研发人员增长的主要原因是什么**
**A** 2022年收购彩晶光电完成后将彩晶光电研发人员纳入统计。
---
## 11. 现金流与差异解释
**Q522022年三大现金流净额分别是多少**
**A** 经营活动-23,646,854.70元;投资活动-844,050,079.34元;筹资活动+1,049,218,073.24元。
**Q53经营活动现金流为何与净利润差异较大**
**A** 报告说明主要由于购买商品、接受劳务支付的现金增加等因素。
---
## 12. 资产负债与受限资产
**Q542022年末资产结构的几个大项是多少**
**A** 货币资金5.51亿元应收账款11.54亿元存货6.70亿元固定资产7.45亿元在建工程4.17亿元商誉6.15亿元等(详见原表)。
**Q55报告期末有哪些主要受限资产合计多少**
**A** 受限资产合计759,059,552.00元,主要包括票据保证金、质押票据、抵押的固定资产/无形资产/在建工程以及质押的长期股权投资以持有彩晶光电60.92%股权质押取得长期借款等)。
---
## 13. 投资并购与合并范围变动
**Q562022年合并范围有哪些变动**
**A** 新设保定康达新材料2022年1月纳入出售天津易远通60%股权2022年2月不再纳入新设康达锦瑞2022年8月纳入收购彩晶光电60.9205%股权2022年8月纳入
**Q57重大股权投资中彩晶光电收购的关键信息是什么**
**A** 通过收购取得彩晶光电60.9205%股权股权投资金额披露为372,530,500.00元;纳入合并报表范围。
**Q58公司是否发生重大资产出售**
**A** 报告期未出售重大资产。
**Q59重大股权出售天津易远通情况如何**
**A** 康达国际供应链以1,815万元向天津唐控科创集团出售天津易远通60%股权,披露为关联交易;对公司整体经营与业绩无重大影响。
---
## 14. 募集资金要点
**Q60报告期涉及哪些募集资金项目/年份?**
**A** 2016年非公开发行募集资金8.5亿元2022年非公开发行募集资金7亿元。
**Q61截至2022年末尚未使用的募集资金余额与去向是什么**
**A** 2016年项目尚未使用余额1,375.01万元存放专户2022年项目尚未使用余额34,493.59万元其中12,000万元用于现金管理、4,000万元用于暂时补充流动资金、其余存放募集资金专户。
**Q62丁基材料项目为何结项并变更投向**
**A** 报告说明市场前景不及预期为优化资源配置与提高资金使用效率公司对丁基材料项目结项并将剩余募集资金18,558.08万元投向“高性能环氧结构胶粘剂扩产项目”和“研发中心扩建项目”。
---
## 15. 子公司/参股公司经营贡献(摘录)
**Q63对公司净利润影响较大的子公司有哪些表现如何**
**A** 报告列示:
* 必控科技报告期营业收入19,642.62万元、净利润4,698.65万元,对整体业绩贡献较大。
* 力源兴达报告期营业收入10,059.81万元、净利润-818.43万元,对整体业绩有一定影响。
---
## 16. 资质与合规(节选)
**Q64公司在安全/环保/质量体系方面有哪些主要证照或认证?**
**A** 报告列示包括安全生产许可证、安全生产标准化证书、危险化学品经营许可证、ISO9001/ISO14001/IATF16949、排污许可证、CNAS实验室认可、GL证书等并披露有效期详见原表
**Q65报告期是否发生重大安全环保事故或非正常停产**
**A** 报告披露全年未发生重大安全环保事故,且不存在非正常停产情形。
---
## 17. 税收优惠(财务报表附注摘录)
**Q66哪些主体适用15%企业所得税优惠税率(高新/西部大开发等)?**
**A** 报告附注披露母公司、本公司部分子公司如必控科技、力源兴达、河北惟新、理日新材、彩晶光电等适用15%税率(高新技术企业或西部大开发等政策口径)。
**Q67哪些主体适用小型微利企业所得税优惠**
**A** 康厦科技、深圳康达电子、康达国际供应链、微相邦、万斯先进新材料、晟宇科技、顺璟投资、璟创投资、天津瑞宏、天津三友、天津康达新材料、瑞贝斯、河北康达新材料、保定康达新材料、惟新半导体、理日新材、康达锦瑞等(以原文列示为准)。
---
## 18. 资产负债表日后事项(财务报表附注摘录)
**Q68报告披露的资产负债表日后事项有哪些类型**
**A** 主要包括部分借款信息披露以及1受让成都赛英科技100%股权的进展披露、2为参股公司申请银行贷款提供担保、3控股子公司与关联方共同对外投资设立合资公司等。
---
## 19. 快速检索:关键数字一览
* 营业收入20222,466,361,756.29 元
* 归母净利润202247,913,477.29 元
* 扣非归母净利润202233,756,789.24 元
* 经营活动现金流净额2022-23,646,854.70 元
* 总资产2022年末5,332,562,034.54 元
* 归母净资产2022年末3,001,624,183.70 元
* 研发费用2022126,419,384.32 元占营收5.13%

View File

@ -1,264 +0,0 @@
# 康达新材2023年年度报告Q&A版
> 说明:本文为对 `md/康达新材2023年年度报告.md` 的要点抽取与问答化重组,便于检索与知识库问答使用;问题为整理者归纳,答案以原文表述与数据为准。
---
## 1. 利润分配
**Q52023年度利润分配预案是什么**
**A** 以实施分配方案时股权登记日“总股本扣减回购专用证券账户股份数”为基数向全体股东每10股派发现金股利0.70元(含税),不送红股,不以资本公积金转增股本。
**Q6本次现金分红的股本基数与现金分红金额是多少**
**A** 分配预案股本基数为297,160,573股现金分红金额为20,801,240.11元(含税)。
---
## 3. 业务版图与战略定位(管理层讨论与分析摘要)
**Q12公司产品主要对应哪些行业**
**A** 公司产品根据特性与终端应用领域/业务类型,分别属于胶粘剂新材料行业、合成树脂行业、电子信息材料行业、电子科技行业。
**Q13公司“主链+第二增长极”的模式是什么?**
**A** 形成“以胶粘剂新材料系列产品为主链、高端电子信息材料为支撑的第二增长极”的发展模式,并在电子科技领域持续完善战略布局与资源联动。
**Q142023年公司在合成树脂领域有什么布局**
**A** 向胶粘剂产业链上游收购并增资大连齐化,进入合成树脂领域;大连齐化以高品质环氧树脂为主,涵盖特种树脂新材料研发、生产、销售、服务。
**Q152023年公司在电子信息材料领域有哪些延伸**
**A** 继2022年收购彩晶光电进入液晶显示材料、医药中间体及电子化学品等领域后2023年收购晶材科技业务涵盖陶瓷生料带、贵金属浆料、瓷粉等。
**Q162023年电子科技板块产业链如何延展**
**A** 收购赛英科技后,形成涵盖电磁兼容、电源模块、电容、微波组件、雷达相关整机等元器件级/部件级/系统级/整机级的业务链条。
---
## 5. 2023年经营回顾要点
**Q222023年公司总体经营表现如何**
**A** 营业收入2,792,525,024.71元同比增长13.22%归母净利润30,315,165.24元同比下降36.66%期末资产总额7,122,936,764.42元同比增长33.57%。
**Q23归母净利润下降的主要原因报告说明是什么**
**A** 胶粘剂板块风电系列产品规模稳中有升、原材料趋稳后板块盈利能力较上年提升;但电子科技与电子信息材料板块行业环境阶段性变化、调整及订单延后等因素叠加,部分公司计提商誉减值准备,对归母净利润产生影响。
**Q24风电胶粘剂与风电一体化材料供应方面有哪些进展**
**A** 风电胶粘剂系列产品继续保持市占率领先风电环氧结构胶、灌注树脂等各类产品销售总量近6万吨海外市场在Siemens Gomesa应用稳定并在LM Windpower批量采购并推进多工厂试用认证。
**Q25包装领域业务表现与海外拓展如何**
**A** 聚氨酯类胶粘剂销售量、销售额同比上升报告期销售量超1万吨覆盖客户超700家海外销售范围扩展至东南亚、中亚等25个国家或地区贸易额增幅达30%。
**Q26消费电子、家电、轨道交通用胶有哪些进展**
**A** 消费电子胶形成多产品线并按客户需求个性化调整与联想、华硕、罗技、韶音等客户协同开发家电用胶围绕美的、格力、海尔等目标客户开始批量供货轨道交通领域通过TB/T2975-2018认证并逐步提升市占率。
**Q27电子信息材料板块有哪些进展**
**A** 彩晶光电混合液晶围绕京东方高世代产线多款产品供货“户外商显”首次小批量出货医药板块受部分中间体停产与行业降价影响下滑但推进新品转化与量产并开展高端中间体研发惟新科技推进大尺寸ITO靶材产线升级扩建及高纯氧化铝靶材项目。
**Q28电子科技板块在型号/研发与产能方面有哪些进展?**
**A** 赛英科技推进多个项目并于2023年7月彭州雷达测试基地投入使用必控科技新研项目近190项力源兴达全年完成项目开发370余项、约50%为国产化改造,并新增大量新需求。
**Q292023年研发投入与创新成果如何**
**A** 研发费用177,605,054.56元占营收6.36%新增授权专利29项发明16项、实用新型13项受理发明专利30项参与制定或修订行业标准1项。
---
## 6. 主要财务指标(合并口径)
**Q302023/2022营业收入分别是多少**
**A** 2023年2,792,525,024.71元2022年2,466,361,756.29元。
**Q312023年归母净利润与扣非归母净利润是多少**
**A** 归母净利润30,315,165.24元;扣非归母净利润-150,073,608.10元。
**Q322023年经营活动现金流净额是多少**
**A** 9,829,020.97元。
**Q332023年基本/稀释每股收益与加权ROE是多少**
**A** 基本每股收益0.100元/股稀释每股收益0.100元/股加权平均净资产收益率1.03%。
**Q342023年末总资产与归母净资产是多少**
**A** 总资产7,122,936,764.42元归属于上市公司股东的净资产2,976,876,747.22元。
**Q35营业收入扣除前后金额是多少**
**A** 2023年营业收入扣除金额156,348,055.39元扣除后金额2,636,176,969.32元。
---
## 7. 分季度主要财务指标(合并口径)
**Q362023年分季度营业收入分别是多少**
**A** Q1 630,942,962.19元Q2 648,773,198.50元Q3 705,360,387.19元Q4 807,448,476.83元。
**Q372023年分季度归母净利润分别是多少**
**A** Q1 -14,847,352.02元Q2 50,891,195.90元Q3 -3,752,562.06元Q4 -1,976,116.58元。
**Q382023年分季度经营活动现金流净额分别是多少**
**A** Q1 -97,845,264.99元Q2 -12,832,682.78元Q3 31,779,967.81元Q4 88,727,000.93元。
---
## 8. 非经常性损益2023年
**Q392023年非经常性损益合计是多少**
**A** 180,388,773.34元。
**Q402023年非经常性损益的主要来源有哪些**
**A** 主要包括:
* 公允价值变动损益123,636,796.27元(报告说明:上海晶材原股东未完成业绩承诺所支付业绩补偿等)。
* 计入当期损益的政府补助14,378,285.97元。
* 收购赛英科技形成的“负商誉”收益44,946,508.24元。
* 非流动资产处置损益-21,818.65元等。
**Q41“其他符合非经常性损益定义的损益项目”是什么**
**A** 本期注销子公司康达晟宇产生的投资收益列示为4,186.14元。
---
## 9. 收入结构与毛利2023年
**Q42按行业看2023年营业收入构成如何**
**A** 胶粘剂1,971,572,392.42元70.60%电子产品261,692,120.15元9.37%复合材料100,701,149.72元3.61%显示材料136,741,920.89元4.90%医药中间体130,962,131.42元4.69%电子化学品18,311,999.63元0.66%LTCC材料16,195,255.08元0.58%其他业务收入156,348,055.40元5.60%)。
**Q43按产品看2023年主要产品收入有哪些**
**A** 环氧胶类1,317,562,900.69元聚氨酯胶类294,258,688.11元电磁兼容产品130,855,841.37元电源模块62,660,839.65元显示材料136,741,920.89元医药中间体130,962,131.42元轻木套材74,331,868.48元等。
**Q44占比10%以上的业务中,胶粘剂板块毛利率是多少?**
**A** 胶粘剂板块毛利率19.59%。
**Q45环氧胶类与聚氨酯胶类毛利率分别是多少**
**A** 环氧胶类毛利率15.64%聚氨酯胶类毛利率22.16%。
**Q46按销售模式看直销与代销占比如何**
**A** 直销2,470,109,362.83元88.45%代销166,067,606.48元5.95%其他业务156,348,055.40元5.60%)。
---
## 10. 主要客户与供应商集中度
**Q47前五名客户集中度如何**
**A** 前五名客户合计销售金额959,309,115.17元占年度销售总额比例34.35%。
**Q48前五名供应商集中度如何**
**A** 前五名供应商合计采购金额488,605,336.23元占年度采购总额比例24.91%。
---
## 11. 费用、研发与人员
**Q492023年四项期间费用销售/管理/财务/研发)分别是多少?**
**A** 销售费用103,138,352.65元管理费用204,042,488.26元财务费用68,578,978.79元研发费用177,605,054.56元。
**Q50上述费用同比大幅增长的主要原因报告说明是什么**
**A** 主要因工资及福利费、股权激励费用摊销,以及股权投资形成的合并子公司增加、融资额增加等因素。
**Q512023年研发人员规模与占比是多少**
**A** 研发人员486人占比25.98%。
**Q52研发人员增加的原因是什么**
**A** 公司收购赛英科技、上海晶材、大连齐化后,将其研发人员纳入统计。
**Q532023年员工总数与结构如何**
**A** 在职员工合计1,871人母公司550人、主要子公司1,321人专业构成含生产人员794人、技术人员547人、销售人员187人等学历含博士16人、硕士90人、本科522人等以原表为准
---
## 12. 现金流(合并口径)
**Q542023年三大现金流净额分别是多少**
**A** 经营活动+9,829,020.97元;投资活动-871,553,996.98元;筹资活动+807,818,595.07元。
**Q55现金及现金等价物净增加额是多少主要原因是什么**
**A** -53,861,976.40元;报告说明主要因归还贷款和股份回购增加等。
**Q56经营活动现金流净额同比上升的原因报告说明是什么**
**A** 主要系购买商品、接受劳务支付的现金减少所致。
---
## 13. 资产负债表要点合并口径2023年末
**Q572023年末主要资产项目有哪些**
**A** 货币资金522,558,226.31元应收账款1,461,666,737.74元存货792,860,649.81元固定资产1,048,809,835.47元在建工程843,036,382.32元商誉776,599,927.54元无形资产418,503,945.02元等。
**Q582023年末主要负债项目有哪些**
**A** 短期借款1,017,747,629.74元一年内到期的非流动负债620,721,942.15元长期借款823,275,169.86元应付账款650,273,652.63元应付票据349,570,289.51元等。
---
## 14. 资产受限情况(节选)
**Q59截至2023年末受限资产合计是多少**
**A** 受限资产合计账面余额968,128,955.76元合计账面价值757,235,603.35元(表中同时列示期初对比数)。
**Q60受限资产主要包括哪些类型**
**A** 主要包括票据保证金/承兑汇票保证金、应收票据/应收款项融资质押、抵押的固定资产与无形资产、抵押的在建工程、质押的长期股权投资如上海晶材67%股权、彩晶光电60.92%股权等融资安排)、以及应收账款质押等。
---
## 15. 投资并购与合并范围变动
**Q612023年合并范围有哪些重要变动**
**A** 报告披露新增纳入惟新半导体唐山2023年2月起、南平鑫天宇2023年4月起、惟新科技唐山2023年5月起、赛英科技2023年5月起、晟铭建筑新材料2023年6月起、裕隆数智2023年8月起、上海晶材2023年9月起、大连齐化及大连齐化国际物流2023年11月起同时晟宇科技注销2023年6月起不再纳入
**Q62报告期内三项重大股权投资收购金额与标的是什么**
**A** 赛英科技100%股权178,311,200.00元上海晶材67%股权388,600,000.00元大连齐化51%股权116,280,000.00元。
**Q63资产减值与商誉相关情况的要点是什么**
**A** 报告列示资产减值-161,189,905.31元,主要因计提存货跌价准备以及上海晶材、必控科技、力源兴达、天津瑞宏等的商誉减值损失。
---
## 16. 募集资金与现金管理(摘要)
**Q64公司涉及哪些募集资金年度与规模**
**A** 2016年非公开发行募集资金总额85,000万元、净额82,743.85万元2022年非公开发行募集资金总额70,000万元、净额69,125万元。
**Q65截至2023年末尚未使用募集资金余额与去向是什么**
**A** 2016年尚未使用余额559.11万元存放募集资金专户2022年尚未使用余额12,308.73万元其中7,000万元用于暂时补充流动资金剩余5,308.73万元存放募集资金专户。
**Q66报告期内是否存在募集资金现金管理委托理财**
**A** 报告披露存在银行理财产品资金来源为募集资金委托理财发生额14,000万元期末未到期余额为0。
**Q67报告期内是否发生变更募集资金投向的重要事项**
**A** 报告披露变更部分募集资金投向11,628万元用于收购大连齐化部分股权并增资增资完成后合计持有大连齐化51%股权。
---
## 17. 公司治理与组织(摘录)
**Q682023年公司董事会结构有何变化**
**A** 为匹配发展战略与业务需求将董事会人数由9名增加至13名并增补新材料、电子信息、战略管理等领域专家。
**Q692023年公司是否披露ESG相关信息**
**A** 报告披露发布《2022年度环境、社会与公司治理报告》万得ESG评级最新得分提升至A。
---
## 18. 风险提示(节选)
**Q70报告提到的“市场竞争加剧风险”是什么**
**A** 胶粘剂行业市场集中度不高、竞争充分,常规型产品竞争加剧,同时国际企业在国内布局;若公司不能保持技术/服务创新与品牌影响力,可能面临客户流失与市场份额下降风险。
---
## 19. 资产负债表日后事项(节选)
**Q71资产负债表日后利润分配如何披露**
**A** 披露拟每10股派息0.7元并以总股本305,402,973股扣减回购专户8,242,400股后基数297,160,573股测算拟派发现金红利20,801,240.11元。
**Q72资产负债表日后与上海晶材业绩补偿相关事项是什么**
**A** 披露上海晶材2023年度未完成业绩承诺交易对方补偿金额15,544万元现金与股权形式其中股权部分对应上海晶材13.4%股权公司对相关商誉计提减值准备12,245.90万元并将补偿款确认为以公允价值计量且其变动计入当期损益的金融资产确认公允价值变动损益12,188.62万元(作为资产负债表日后调整事项)。
---
## 20. 快速检索:关键数字一览
* 营业收入20232,792,525,024.71 元
* 归母净利润202330,315,165.24 元
* 扣非归母净利润2023-150,073,608.10 元
* 非经常性损益合计2023180,388,773.34 元
* 经营活动现金流净额20239,829,020.97 元
* 投资活动现金流净额2023-871,553,996.98 元
* 筹资活动现金流净额2023807,818,595.07 元
* 总资产2023年末7,122,936,764.42 元
* 归母净资产2023年末2,976,876,747.22 元
* 研发费用2023177,605,054.56 元(占营收 6.36%

View File

@ -1,317 +0,0 @@
# 康达新材2024年年度报告Q&A版
> 说明:本文为对 `md/康达新材2024年年度报告.md` 的要点抽取与问答化重组,便于检索与知识库问答使用;问题为整理者归纳,答案以原文表述与数据为准。
---
## 1. 重要提示与利润分配
**Q1年度报告由谁保证真实、准确、完整**
**A** 公司董事会、监事会及董事、监事、高级管理人员保证年度报告内容真实、准确、完整,不存在虚假记载、误导性陈述或重大遗漏,并承担个别和连带的法律责任。
**Q2公司负责人及财务负责人对财务报告作了什么声明**
**A** 公司负责人王建祥、主管会计工作负责人宋兆庆及会计机构负责人(会计主管人员)张国强声明:保证本年度报告中财务报告真实、准确、完整。
**Q3董事出席情况如何**
**A** 所有董事均已出席审议本报告的董事会会议。
**Q4前瞻性陈述意味着什么**
**A** 报告所涉未来计划、发展战略等前瞻性陈述不构成公司对投资者的实质承诺,投资者及相关人士应保持风险认识,并理解计划、预测与承诺之间的差异。
**Q5公司是否提示了经营风险**
**A** 报告第三节“管理层讨论与分析”中“公司面临的风险和应对措施”部分描述了公司未来经营中可能面临的风险,提示投资者关注。
**Q62024年度利润分配现金分红/送转)计划是什么?**
**A** 公司计划不派发现金红利,不送红股,不以公积金转增股本。
---
## 2. 公司概况与信息披露
**Q7公司简称、股票代码与上市交易所是什么**
**A** 股票简称康达新材股票代码002669上市交易所深圳证券交易所。
**Q8公司名称、法定代表人、注册地址/办公地址是什么?**
**A** 公司名称:康达新材料(集团)股份有限公司;法定代表人:王建祥;注册地址/办公地址上海市奉贤区雷州路169号。
**Q9公司网址与电子信箱是什么**
**A** 公司网址:<http://www.shkdchem.com>电子信箱kdxc@shkdchem.com。
**Q10董事会秘书与证券事务代表是谁联系方式是什么**
**A** 董事会秘书沈一涛证券事务代表刘洁联系地址上海市浦东新区五星路707弄御河企业公馆A区3号楼电话021-50770196 / 021-50779159传真021-50770183邮箱kdxc@shkdchem.com。
**Q11年度报告披露渠道与备置地点在哪里**
**A** 披露网站深圳证券交易所https://www.szse.cn与巨潮资讯网http://www.cninfo.com.cn披露媒体《证券时报》《证券日报》《中国证券报》《上海证券报》备置地点上海市浦东新区五星路707弄御河企业公馆A区3号楼董事会办公室。
**Q12公司控股股东与实际控制人是谁**
**A** 控股股东为唐山工业控股集团有限公司(唐山工控,原名唐山金控产业发展集团有限公司);实际控制人为唐山市国资委。
---
## 3. 主营业务与战略定位(摘要)
**Q13公司主要业务板块是什么**
**A** 公司主要业务分为胶粘剂与特种树脂新材料、电子信息材料、电子科技三大板块。
**Q14胶粘剂业务主要产品及应用领域有哪些**
**A** 产品涵盖环氧树脂胶、聚氨酯胶、丙烯酸酯胶、SBS胶、热熔胶、水性胶等并包括环氧树脂复合材料、聚氨酯复合材料及聚酰亚胺材料等新材料系列应用于风电叶片制造、包装材料、轨道交通、船舶工程、汽车、电子电器、机械设备、建筑装饰及工业维修等。
**Q15合成树脂业务大连齐化主要产品系列是什么**
**A** 产品主要分为双酚A型环氧树脂、耐热型环氧树脂和特种环氧树脂三大系列涵盖双酚A型液体/固体、溴化、邻甲酚醛等品种,可应用于复合材料、涂料与涂层、粘合剂、电子电气等领域。
**Q16电子信息材料业务覆盖哪些产品方向**
**A** 电子信息材料领域包含液晶显示材料、医药中间体、陶瓷生料带、贵金属浆料、特种显示材料及电子化学品等研发、生产与销售。
**Q17电子科技业务覆盖哪些产品方向**
**A** 电子科技领域主营为电磁兼容、电源模块、微波组件、雷达相关整机等电子产品的研发、生产与销售。
**Q18公司总体战略报告表述如何概括**
**A** 报告提出以“新材料+电子科技”为主线,打造国家级专精特新“小巨人”企业集群;推动从单一胶粘剂产品向高端新材料、从核心零部件向系统集成、从国内为主向国际化布局的转型。
---
## 4. 行业环境(摘录)
**Q19胶粘剂行业“十四五”目标报告引用是什么**
**A** 产量年均增长率约4.2%销售额年均增长率约4.3%到2025年末行业高附加值产品产值比例达到40%以上,并推动水基、热熔、无溶剂等绿色方向。
**Q20环氧树脂行业的供需与国产替代机会报告观点是什么**
**A** 电子工业、汽车产业等带动需求增长;适用性强、性能稳定的高品质环氧树脂仍供不应求,部分电子元件封装、覆铜板等领域产品仍依赖进口,具备国产替代机会。
**Q21LTCC材料国产化为何被认为“需求迫切”**
**A** LTCC材料在材料一致性、高频损耗率等指标上上游原材料市场长期被海外厂商主导具备规模化稳定供货能力并获市场认可的国内企业仍稀缺在高性能雷达自主化、航天载荷轻量化等战略领域将释放市场空间。
**Q22ITO靶材为何被描述为“卡脖子”技术之一**
**A** 溅射靶材行业技术壁垒与客户认证壁垒高全球高纯溅射靶材市场长期被海外厂商控制大尺寸高性能ITO靶材被报道为“卡脖子”技术之一并列入工信部重点新材料首批次应用示范指导目录2019年版
**Q23军工电子行业需求驱动报告引用是什么**
**A** 国防支出稳步增长为装备发展提供支撑报告引用“2025年全国一般公共预算安排国防支出1.81万亿元同比增7.2%”来源2024年3月5日公布的预算执行情况与预算草案报告
---
## 5. 2024年经营回顾要点
**Q242024年公司营业收入与利润总体表现如何**
**A** 营业收入3,101,062,179.20元同比增长11.05%;归母净利润-246,173,519.93元,同比下降-912.05%;扣非归母净利润-308,264,197.06元。
**Q25公司解释的亏损主要原因有哪些**
**A** 报告指出主要原因包括:对存在减值迹象的子公司商誉资产组组合进行减值测试并计提商誉减值;受市场环境影响,电子信息材料、电子科技板块下游客户订单交付减少或延期;新建生产基地处于产能爬坡阶段,对应固定资产折旧及融资贷款利息费用较大等。
**Q26风电叶片制造领域胶粘剂板块有哪些关键进展**
**A** 报告称国内市场份额第一地位稳固风电结构胶全年销售量4万吨高性能胶D-2新品全面推出销量提升至结构胶整体销量的17%风电环氧灌注树脂全年销售量4.5万吨同比上升90%以上连续三年实现翻倍增长市场份额提升至12%,晋升行业前四;并推进海外工厂认证/验证如LM Windpower、GE、Nordex等
**Q27包装领域业务有哪些进展**
**A** 报告称无溶剂复膜胶销售量超万吨、市场占有率保持领先;组建专业技术服务团队,为客户定制复膜胶解决方案;并持续推进油墨产品研发体系与整体解决方案能力。
**Q28电子信息材料板块在国产替代方面有哪些进展**
**A** 惟新科技建成30吨高纯度ITO靶材生产线完成OLED面板头部企业G6代线ITO靶材生产验证关键性能指标优于行业同等规格并完成河北省重点研发计划课题验收同时推进CMP氧化铈抛光液核心技术攻关。
**Q29电子科技板块在“低空经济/安防”等方向有哪些描述?**
**A** 报告称赛英科技通过“军民协同、双向赋能”推进市场突破FOD雷达在大兴机场应用多年并形成国家标准国内机场将逐步列装4D凝视雷达用于“低慢小”目标监控任务并在反无系统中大量应用。
---
## 6. 主要会计数据与财务指标(合并口径)
**Q302024/2023营业收入分别是多少**
**A** 2024年3,101,062,179.20元2023年2,792,525,024.71元。
**Q312024年归母净利润与扣非归母净利润是多少**
**A** 归母净利润-246,173,519.93元;扣非归母净利润-308,264,197.06元。
**Q322024年经营活动现金流净额是多少**
**A** 498,667,285.91元。
**Q332024年基本/稀释每股收益与加权ROE是多少**
**A** 基本每股收益-0.824元/股;稀释每股收益-0.824元/股;加权平均净资产收益率-8.59%。
**Q342024年末总资产与归母净资产是多少**
**A** 总资产6,940,150,195.69元归属于上市公司股东的净资产2,727,894,289.21元。
**Q352024年营业收入扣除前后金额是多少**
**A** 营业收入扣除金额132,825,438.14元扣除后金额2,968,236,741.06元。
---
## 7. 分季度主要财务指标(合并口径)
**Q362024年分季度营业收入分别是多少**
**A** Q1 535,607,900.26元Q2 826,777,196.06元Q3 816,474,450.24元Q4 922,202,632.64元。
**Q372024年分季度归母净利润分别是多少**
**A** Q1 -24,793,535.64元Q2 -31,717,467.21元Q3 -19,966,135.18元Q4 -169,696,381.90元。
**Q382024年分季度经营活动现金流净额分别是多少**
**A** Q1 73,400,210.80元Q2 214,356,837.30元Q3 139,941,585.62元Q4 70,968,652.19元。
---
## 8. 非经常性损益2024年
**Q392024年非经常性损益合计是多少**
**A** 62,090,677.13元。
**Q402024年非经常性损益主要由哪些项目构成**
**A** 主要包括:
* 非流动性资产处置损益40,430,252.31元(主要系报告期内转让彩晶光电产生的处置收益)。
* 计入当期损益的政府补助25,980,131.98元。
* 公允价值变动损益等269,346.81元。
* 单独进行减值测试的应收款项减值准备转回3,177,638.34元。
* 其他营业外收入和支出-3,759,143.23元。
* 减所得税影响额2,303,077.58元少数股东权益影响额税后1,704,471.50元。
---
## 9. 营业收入结构与毛利2024年
**Q41按行业看2024年营业收入构成如何**
**A** 胶粘剂2,252,028,435.31元72.62%合成树脂189,307,031.23元6.10%电子产品262,819,931.17元8.48%复合材料15,841,726.18元0.51%显示材料90,438,229.45元2.92%医药中间体102,507,074.51元3.31%电子化学品11,390,131.19元0.37%LTCC材料43,904,182.03元1.42%其他业务132,825,438.13元4.28%)。
**Q42按产品看2024年主要产品收入有哪些**
**A** 环氧胶类1,570,432,237.01元50.64%聚氨酯胶类312,452,673.98元10.08%丙烯酸胶类92,683,079.29元SBS胶类110,022,477.65元水性胶类56,581,632.93元合成树脂189,307,031.23元电源模块83,375,168.43元电磁兼容产品86,020,868.14元微波组件及系统93,423,894.60元LTCC材料43,904,182.03元等。
**Q43按地区看2024年收入分布有哪些重点**
**A** 华北地区895,953,680.06元28.89%华东地区782,609,545.75元25.24%华中地区338,200,626.93元10.91%国外地区91,915,079.33元2.96%)等(以原表为准)。
**Q44按销售模式看直销与分销占比如何**
**A** 直销2,809,752,244.68元90.61%分销158,484,496.39元5.11%其他业务132,825,438.13元4.28%)。
**Q45占比10%以上的业务/产品毛利率如何?**
**A** 胶粘剂毛利率17.84%环氧胶类毛利率15.92%聚氨酯胶类毛利率27.88%直销毛利率16.18%(对应表中同比变动亦已披露)。
**Q46报告期主营业务统计口径有什么变化**
**A** 2024年将“合成树脂”从胶粘剂行业与环氧胶类产品中单独列示口径变化原因之一是2024年合并大连齐化全年数据且列示为对外销售形成的营业收入。
---
## 10. 产销数据(同比大幅变动项)
**Q47胶粘剂与合成树脂的销量同比为何变化较大**
**A** 胶粘剂产品销量/产量增加主要为风电结构胶、灌注树脂及其他胶种市场开拓所致库存量减少主要为年底销量增幅较快所致合成树脂增幅较大主要为2023年11月大连齐化纳入合并范围而2024年合并大连齐化全年数据所致。
---
## 11. 主要客户与供应商集中度
**Q48前五名客户集中度如何**
**A** 前五名客户合计销售金额1,170,113,577.70元占年度销售总额比例37.73%。
**Q49前五名供应商集中度与关联采购占比如何**
**A** 前五名供应商合计采购金额840,525,802.96元占年度采购总额比例35.30%前五名供应商采购额中关联方采购额占年度采购总额比例21.93%。
---
## 12. 期间费用、研发与人员
**Q502024年销售/管理/财务/研发费用分别是多少?**
**A** 销售费用102,000,705.02元管理费用232,581,720.53元财务费用95,545,381.14元研发费用203,525,998.94元。
**Q51研发投入规模与占比如何**
**A** 研发投入金额203,525,998.94元占营业收入比例6.56%。
**Q52研发人员规模与占比是多少**
**A** 研发人员376人占比22.97%。
**Q53研发人员较上年减少的原因是什么**
**A** 报告说明公司出售彩晶光电股权彩晶光电不再纳入公司合并报表范围其研发人员未统计入2024年。
**Q54报告期末员工总数与结构如何**
**A** 在职员工合计1,637人母公司546人、主要子公司1,091人专业构成含生产人员662人、销售人员188人、技术人员444人等学历含博士12人、硕士70人、本科483人等以原表为准
---
## 13. 现金流(合并口径)
**Q552024年三大现金流净额分别是多少**
**A** 经营活动+498,667,285.91元;投资活动-358,595,995.08元;筹资活动+137,480,803.15元。
**Q562024年现金及现金等价物净增加额是多少**
**A** 276,194,234.34元。
**Q57经营/投资/筹资现金流变化的主要原因(报告说明)是什么?**
**A** 经营性净流入增加主要系购买商品、接受劳务支付的现金减少;投资活动净流出同比减少主要系处置子公司取得现金收入增加、取得子公司及联营单位支付现金减少;筹资活动净流入同比减少主要系偿还银行借款及利息支出增加。
---
## 14. 资产负债表要点合并口径2024年末
**Q582024年末主要资产项目有哪些**
**A** 货币资金799,834,198.31元应收账款1,877,790,764.09元存货545,690,424.46元固定资产1,116,686,210.01元在建工程715,274,766.37元商誉437,307,088.79元无形资产328,426,810.26元等。
**Q592024年末主要负债项目有哪些**
**A** 短期借款1,042,105,372.47元应付票据570,729,889.37元应付账款941,500,280.13元一年内到期的非流动负债390,026,280.20元长期借款772,284,891.01元等。
**Q60报告期内重大资产减值情况是什么**
**A** 报告列示资产减值损失-194,887,938.64元,并说明主要系计提存货跌价准备以及上海晶材、必控科技、力源兴达的商誉减值损失等。
---
## 15. 公允价值计量与业绩补偿(摘要)
**Q612024年末交易性金融资产业绩补偿款余额是多少**
**A** 交易性金融资产121,886,200.00元(业绩承诺补偿款)。
**Q62报告对交易性金融资产“其他变动”的说明是什么**
**A** 报告说明:交易性金融资产(不含衍生金融资产)其他变动是上海晶材原股东未完成业绩承诺所支付业绩补偿。
---
## 16. 资产权利受限情况(摘要)
**Q63截至2024年末受限资产合计是多少**
**A** 合计账面余额999,166,089.97元合计账面价值848,820,322.87元。
**Q64受限资产主要包括哪些类型**
**A** 主要包括:抵押的固定资产/无形资产/在建工程,质押的长期股权投资、应收款项融资质押、应收账款质押,以及票据保证金等(明细见原表“期末说明”)。
---
## 17. 合并范围变动与重大股权交易
**Q652024年合并范围发生了哪些主要变动**
**A** 报告披露璟创投资、康达新材料保定、裕隆数智、顺璟投资、万斯新材料等注销或退出不再纳入新增纳入康达新材泰国2024年12月增资取得贵州盛顺82%并间接取得贵州麟拓63%纳入合并并披露出售彩晶光电股权后将自2025年1月起不再纳入。
**Q66出售彩晶光电股权的交易对手、比例与价格是多少**
**A** 公司全资子公司新材料科技向唐山裕隆光电科技有限公司出售所持西安彩晶光电科技股份有限公司66.9996%股权对价为人民币40,588.00万元。
**Q67出售彩晶光电股权对资金用途的影响报告说明是什么**
**A** 报告说明:不影响正常生产经营活动;所得资金将用于归还银行贷款及补充流动资金,降低管理成本,提高盈利能力。
---
## 18. 募集资金使用(摘要)
**Q68公司涉及哪些募集资金年度与规模**
**A** 2016年向特定对象发行股票募集资金总额85,000万元、净额82,743.85万元2022年向特定对象发行股票募集资金总额70,000万元、净额69,125万元。
**Q69截至2024年末尚未使用募集资金余额与去向是什么**
**A** 2016年募集资金已使用完毕2022年募集资金尚未使用余额4,953.67万元其中4,500万元用于暂时补充流动资金剩余453.67万元存放于募集资金专户。
---
## 19. 公司治理与ESG摘录
**Q70公司在分红政策与股东回报规划方面有哪些安排**
**A** 报告披露修订《公司章程》中现金分红相关条款并制定《未来三年股东分红回报规划2024-2026年》。
**Q71报告披露的ESG相关信息与奖项有哪些**
**A** 报告披露公司发布《2023年度环境、社会与公司治理报告》、万得ESG评级保持A级并获得“ESG金牛奖百强”等。
**Q72公司总股本在2024年是否发生变化原因是什么**
**A** 报告披露2024年6月完成注销部分回购股份2,002,973股占注销前总股本0.66%注销完成后总股本由305,402,973股变更为303,400,000股。
---
## 20. 快速检索:关键数字一览
* 营业收入20243,101,062,179.20 元
* 归母净利润2024-246,173,519.93 元
* 扣非归母净利润2024-308,264,197.06 元
* 非经常性损益合计202462,090,677.13 元
* 经营活动现金流净额2024498,667,285.91 元
* 投资活动现金流净额2024-358,595,995.08 元
* 筹资活动现金流净额2024137,480,803.15 元
* 现金及现金等价物净增加额2024276,194,234.34 元
* 总资产2024年末6,940,150,195.69 元
* 归母净资产2024年末2,727,894,289.21 元
* 研发费用2024203,525,998.94 元(占营收 6.56%

View File

@ -1,220 +0,0 @@
# 康达新材2025年第一季度报告Q&A版
> 说明:本文为对 `md/康达新材2025年一季度报告.md` 的要点抽取与问答化重组,便于检索与知识库问答使用;问题为整理者归纳,答案以原文表述与数据为准。
---
## 1. 重要提示与审计情况
**Q1公司对一季度报告信息披露作了什么承诺**
**A** 本公司及董事会全体成员保证信息披露内容真实、准确、完整,没有虚假记载、误导性陈述或重大遗漏。
**Q2谁对季度报告的真实、准确、完整承担责任**
**A** 董事会、监事会及董事、监事、高级管理人员保证季度报告真实、准确、完整,不存在虚假记载、误导性陈述或重大遗漏,并承担个别和连带的法律责任。
**Q3公司负责人及财务负责人对财务信息作了什么声明**
**A** 公司负责人、主管会计工作负责人及会计机构负责人(会计主管人员)声明:保证季度报告中财务信息真实、准确、完整。
**Q42025年第一季度报告是否经过审计**
**A** 否,第一季度报告未经审计。
---
## 2. 主要会计数据与财务指标(合并口径)
**Q52025年第一季度营业收入是多少同比如何**
**A** 营业收入877,010,301.56元上年同期535,607,900.26元同比增长63.74%。
**Q62025年第一季度归母净利润是多少同比如何**
**A** 归属于上市公司股东的净利润6,371,842.98元;上年同期-24,793,535.64元同比125.70%。
**Q72025年第一季度扣非归母净利润是多少同比如何**
**A** 扣除非经常性损益的归母净利润3,363,744.00元;上年同期-26,427,485.42元同比112.73%。
**Q82025年第一季度经营活动现金流净额是多少同比如何**
**A** 经营活动产生的现金流量净额-243,787,510.86元上年同期73,400,210.80元;同比-432.13%。
**Q92025年第一季度每股收益基本/稀释)是多少?**
**A** 基本每股收益0.021元/股稀释每股收益0.021元/股(上年同期均为-0.083元/股)。
**Q102025年第一季度加权平均净资产收益率是多少**
**A** 0.24%(上年同期-0.84%)。
**Q112025年3月31日总资产与归母净资产是多少较期初如何变化**
**A** 总资产6,747,360,816.59元较2024年末6,940,150,195.69元下降2.78%归属于上市公司股东的所有者权益2,724,565,896.80元较2024年末2,727,894,289.21元下降0.12%。
---
## 3. 非经常性损益2025年一季度
**Q12本报告期非经常性损益合计是多少**
**A** 3,008,098.98元。
**Q13非经常性损益中“非流动性资产处置损益”是多少**
**A** 707,479.18元。
**Q14计入当期损益的政府补助是多少**
**A** 1,064,112.95元。
**Q15本期金融资产/金融负债相关公允价值变动及处置损益(报告说明)是什么?**
**A** 2,000,000.00元,报告说明为“收到参股子公司上年度分红款”。
**Q16单独进行减值测试的应收款项减值准备转回是多少**
**A** 20,000.00元。
**Q17其他营业外收入和支出净额是多少**
**A** -252,725.49元。
**Q18非经常性损益的所得税影响额与少数股东权益影响额税后分别是多少**
**A** 所得税影响额529,763.22元少数股东权益影响额税后1,004.44元。
**Q19是否存在其他符合非经常性损益定义的项目或将其界定为经常性损益的情形**
**A** 不存在。
---
## 4. 主要指标变动原因(报告披露)
### 4.1 资产负债表项目变动
**Q20货币资金为何下降下降多少**
**A** 2025年3月31日495,660,929.09元较2024年末799,834,198.31元下降38.03%;主要系报告期内归还银行贷款和支付原材料采购款增加所致。
**Q21预付款项为何上升上升多少**
**A** 32,868,552.07元较2024年末20,329,269.33元上升61.68%;主要系预付原材料采购款增加所致。
**Q22其他应收款为何大幅下降**
**A** 16,975,655.72元较2024年末170,367,423.35元下降90.04%;主要系收到出售子公司股权转让款所致。
**Q23投资性房地产为何为0**
**A** 期末为0.00元较2024年末4,606,245.07元下降100.00%;主要系对外出租房屋减少所致。
**Q24固定资产为何上升、在建工程为何下降**
**A** 固定资产1,497,341,452.78元较2024年末1,116,686,210.01元上升34.09%在建工程318,514,634.19元较2024年末715,274,766.37元下降55.47%;主要系在建工程转固所致。
**Q25其他非流动资产为何上升**
**A** 22,099,433.13元较2024年末9,721,396.37元上升127.33%;主要系预付设备款、工程款增加所致。
**Q26预收款项为何大幅下降、合同负债为何大幅上升**
**A** 预收款项178,176.12元较2024年末70,466,949.54元下降99.75%主要系预收客户货款减少合同未签订合同负债120,156,064.23元较2024年末35,733,227.19元上升236.26%,主要系预收客户货款增加(合同已签订)。
**Q27其他应付款为何下降**
**A** 9,858,085.28元较2024年末14,836,889.80元下降33.56%;主要系往来款减少所致。
**Q28库存股为何上升**
**A** 36,909,368.73元较2024年末23,668,633.73元上升55.94%;主要系报告期内公司回购股份增加所致。
**Q29其他综合收益为何上升**
**A** 446,738.51元较2024年末142,776.11元上升212.89%;主要系外币财务报表折算差额增加所致。
### 4.2 利润表项目变动
**Q30营业收入同比大幅增长的原因是什么**
**A** 主要系胶粘剂产品中风电胶系列产品订单增加等因素影响,公司销售规模有所上升。
**Q31营业成本同比上升的原因是什么**
**A** 主要系营业收入增加营业成本随之增加所致本期737,923,975.48元上年同期436,730,929.55元,同比+68.97%。
**Q32信用减值损失为何由正转负**
**A** 本期信用减值损失-3,694,467.19元上年同期6,345,252.90元;主要系期末应收款项增减变动导致计提减值同步变动所致。
**Q33资产处置收益为何增加**
**A** 本期资产处置收益707,844.97元上年同期217,756.26元,同比+225.06%;主要系处置无法使用的资产增加所致。
**Q34所得税费用为何增长**
**A** 本期所得税费用8,903,252.97元上年同期2,562,419.33元,同比+247.45%;主要系利润总额增加导致所得税费用增加。
**Q35归母净利润同比转正的原因是什么**
**A** 报告说明主要系营业收入大幅增加,导致净利润同时增加所致。
**Q36其他综合收益的税后净额为何大幅增加**
**A** 本期303,962.40元上年同期286.65元;主要系外币财务报表折算差额增加所致。
---
## 5. 股东信息截至2025年3月31日
**Q37报告期末普通股股东总数是多少**
**A** 22,893户。
**Q38控股股东是谁持股比例与数量是多少是否存在质押**
**A** 唐山工业控股集团有限公司持股87,421,621股占28.81%质押39,918,579股。
**Q39报告披露的前10名股东部分有哪些**
**A** 例如第四期员工持股计划4,673,900股1.54%、耿殿根4,578,168股1.51%、张立岗4,324,750股1.43%、第五期员工持股计划4,289,000股1.41%、第三期员工持股计划3,241,100股1.07%)等(以原表为准)。
**Q40前十名股东之间是否存在关联关系或一致行动关系**
**A** 公司未知前十名股东之间是否存在关联关系,也未知是否属于一致行动人。
**Q41是否披露融资融券参与情况**
**A** 披露股东程洁通过信用账户持有1,667,000股股东周新勇通过信用账户持有1,567,800股。
---
## 6. 其他重要事项(报告披露)
**Q42公司董事会、监事会换届及高管选举的时间节点是什么**
**A** 2025年1月24日召开第五届董事会第四十一次会议、第五届监事会第三十三次会议审议换届相关议案并提交2025年2月10日临时股东大会审议通过2025年2月11日召开第六届董事会第一次会议、第六届监事会第一次会议选举董事长、监事会主席及高级管理人员。
**Q43第八期股份回购方案的核心参数是什么**
**A** 回购价格不超过15.00元/股回购资金总额不低于10,000万元、不高于20,000万元资金来源为自有资金及回购专项贷款。
**Q44首次实施回购发生在何时回购了多少股、成交金额多少**
**A** 2025年3月4日首次实施回购回购284,000股占总股本0.0936%最高9.87元/股、最低9.57元/股成交金额2,760,130元不含交易费用
**Q45截至2025年3月31日累计回购多少股、金额多少**
**A** 累计回购1,372,300股占总股本0.4523%最高9.99元/股、最低9.29元/股成交金额13,240,735元不含交易费用
**Q46报告披露的“回购比例达到2%”事项是什么?**
**A** 公司于2025年4月15日披露《关于回购股份比例达到2%暨回购进展公告》累计回购股份数量已超过公司总股本的2%,后续将根据市场情况继续按方案实施。
**Q47控股股东增持计划2024/2025两段主要内容是什么**
**A** 2024年7月9日至2025年1月8日唐山工控以集中竞价累计增持3,266,500股占总股本1.08%增持金额约3,010.75万元2025年1月18日起6个月内继续增持计划金额不低于1,000万元且不超过2,000万元方式包括集中竞价和大宗交易等截至目前唐山工控持股87,421,621股占28.81%。
**Q48报告披露的关联交易/共同投资事项是什么?**
**A** 2025年1月24日审议通过全资子公司必控科技与关联方以0元对价共同收购四川忠华智能科技有限公司股权并增资唐控智能认购注册资本2,800万元持股35%必控科技认购2,800万元持股35%其中固定资产作价2,600万元风范晶樱认购1,600万元持股20%海南远领与海南可为分别认购400万元各持股5%;截至目前工商变更登记手续已办理完毕。
---
## 7. 财务报表关键数字速查(合并口径)
**Q49合并资产负债表中期末主要资产项目有哪些关键数值**
**A** 货币资金495,660,929.09元应收票据266,700,534.77元应收账款2,034,639,856.21元应收款项融资208,971,494.43元存货619,751,020.17元固定资产1,497,341,452.78元在建工程318,514,634.19元无形资产320,537,081.21元商誉437,307,088.79元。
**Q50合并资产负债表中期末主要负债项目有哪些关键数值**
**A** 短期借款1,070,196,811.34元应付票据449,338,097.20元应付账款1,080,690,587.96元合同负债120,156,064.23元一年内到期的非流动负债359,701,421.02元长期借款560,844,522.99元。
**Q51期末归母所有者权益合计是多少少数股东权益是多少**
**A** 归属于母公司所有者权益合计2,724,565,896.80元少数股东权益173,340,070.82元。
**Q52合并利润表中营业利润、利润总额与净利润分别是多少**
**A** 营业利润11,044,437.99元利润总额10,791,346.71元净利润1,888,093.74元。
**Q53归属母公司净利润与少数股东损益分别是多少**
**A** 归属于母公司所有者的净利润6,371,842.98元;少数股东损益-4,483,749.24元。
**Q54合并现金流量表中三大现金流净额分别是多少**
**A** 经营活动现金流净额-243,787,510.86元投资活动现金流净额92,049,529.25元;筹资活动现金流净额-164,746,680.98元。
**Q55投资活动现金流中处置子公司及其他营业单位收到的现金净额是多少**
**A** 162,352,000.00元。
**Q56筹资活动现金流中取得借款收到的现金、偿还债务支付的现金分别是多少**
**A** 取得借款收到的现金478,085,262.74元偿还债务支付的现金660,256,118.51元。
**Q57本期现金及现金等价物净增加额、期末余额分别是多少**
**A** 净增加额-316,378,429.93元期末余额405,856,258.35元。
---
## 8. 快速检索:关键指标一览
* 营业收入2025Q1877,010,301.56 元
* 归母净利润2025Q16,371,842.98 元
* 扣非归母净利润2025Q13,363,744.00 元
* 非经常性损益合计2025Q13,008,098.98 元
* 经营活动现金流净额2025Q1-243,787,510.86 元
* 总资产2025-03-316,747,360,816.59 元
* 归母净资产2025-03-312,724,565,896.80 元
* 普通股股东总数22,893
* 控股股东持股87,421,621 股28.81%

View File

@ -1,25 +0,0 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
def add_cors_middleware(app: FastAPI):
"""
添加跨域中间件
:param app: FastAPI对象
:return:
"""
# 前端页面url
origins = [
'http://localhost:80',
'http://127.0.0.1:80',
]
# 后台api允许跨域
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)

View File

@ -1,17 +0,0 @@
from fastapi import FastAPI
def add_gzip_middleware(app: FastAPI):
"""
添加gzip压缩中间件 - 已禁用
注意: 由于SSE流式响应需要实时传输gzip压缩被禁用
SSE数据流很小压缩意义不大反而会影响实时性
:param app: FastAPI对象
:return:
"""
# 暂时禁用GZip中间件以支持SSE流式响应
# 如果需要重新启用,请取消下面的注释
# app.add_middleware(GZipMiddleware, minimum_size=1000, compresslevel=9)
pass

View File

@ -1,16 +0,0 @@
from fastapi import FastAPI
from middlewares.cors_middleware import add_cors_middleware
from middlewares.gzip_middleware import add_gzip_middleware
from middlewares.trace_middleware import add_trace_middleware
def handle_middleware(app: FastAPI):
"""
全局中间件处理
"""
# 加载跨域中间件
add_cors_middleware(app)
# 加载gzip压缩中间件
add_gzip_middleware(app)
# 加载trace中间件
add_trace_middleware(app)

View File

@ -1,17 +0,0 @@
from fastapi import FastAPI
from .ctx import TraceCtx
from .middle import TraceASGIMiddleware
__all__ = ('TraceASGIMiddleware', 'TraceCtx')
__version__ = '0.1.0'
def add_trace_middleware(app: FastAPI):
"""
添加trace中间件
:param app: FastAPI对象
:return:
"""
app.add_middleware(TraceASGIMiddleware)

View File

@ -1,23 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: peng
@file: ctx.py
@time: 2025/1/17 16:57
"""
import contextvars
from uuid import uuid4
CTX_REQUEST_ID: contextvars.ContextVar[str] = contextvars.ContextVar('request-id', default='')
class TraceCtx:
@staticmethod
def set_id():
_id = uuid4().hex
CTX_REQUEST_ID.set(_id)
return _id
@staticmethod
def get_id():
return CTX_REQUEST_ID.get()

View File

@ -1,47 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: peng
@file: middle.py
@time: 2025/1/17 16:57
"""
from functools import wraps
from starlette.types import ASGIApp, Message, Receive, Scope, Send
from .span import get_current_span, Span
class TraceASGIMiddleware:
"""
fastapi-example:
app = FastAPI()
app.add_middleware(TraceASGIMiddleware)
"""
def __init__(self, app: ASGIApp) -> None:
self.app = app
@staticmethod
async def my_receive(receive: Receive, span: Span):
await span.request_before()
@wraps(receive)
async def my_receive():
message = await receive()
await span.request_after(message)
return message
return my_receive
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
if scope['type'] != 'http':
await self.app(scope, receive, send)
return
async with get_current_span(scope) as span:
handle_outgoing_receive = await self.my_receive(receive, span)
async def handle_outgoing_request(message: 'Message') -> None:
await span.response(message)
await send(message)
await self.app(scope, handle_outgoing_receive, handle_outgoing_request)

View File

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
"""
@author: peng
@file: span.py
@time: 2025/1/17 16:57
"""
from contextlib import asynccontextmanager
from starlette.types import Scope, Message
from .ctx import TraceCtx
class Span:
"""
整个http生命周期
request(before) --> request(after) --> response(before) --> response(after)
"""
def __init__(self, scope: Scope):
self.scope = scope
async def request_before(self):
"""
request_before: 处理header信息等, 如记录请求体信息
"""
TraceCtx.set_id()
async def request_after(self, message: Message):
"""
request_after: 处理请求bytes 如记录请求参数
example:
message: {'type': 'http.request', 'body': b'{\r\n "name": "\xe8\x8b\x8f\xe8\x8b\x8f\xe8\x8b\x8f"\r\n}', 'more_body': False}
"""
return message
async def response(self, message: Message):
"""
if message['type'] == "http.response.start": -----> request-before
pass
if message['type'] == "http.response.body": -----> request-after
message.get('body', b'')
pass
"""
if message['type'] == 'http.response.start':
message['headers'].append((b'request-id', TraceCtx.get_id().encode()))
return message
@asynccontextmanager
async def get_current_span(scope: Scope):
yield Span(scope)

View File

@ -1,266 +0,0 @@
import inspect
import json
import os
import requests
import time
from datetime import datetime
from fastapi import Request
from fastapi.responses import JSONResponse, ORJSONResponse, UJSONResponse
from functools import lru_cache, wraps
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Any, Callable, Literal, Optional
from user_agents import parse
from config.enums import BusinessType
from config.env import AppConfig
from exceptions.exception import LoginException, ServiceException, ServiceWarning
from module_admin.entity.vo.log_vo import LogininforModel, OperLogModel
from module_admin.service.log_service import LoginLogService, OperationLogService
from module_admin.service.login_service import LoginService
from utils.log_util import logger
from utils.response_util import ResponseUtil
class Log:
"""
日志装饰器
"""
def __init__(
self,
title: str,
business_type: BusinessType,
log_type: Optional[Literal['login', 'operation']] = 'operation',
):
"""
日志装饰器
:param title: 当前日志装饰器装饰的模块标题
:param business_type: 业务类型OTHER其它 INSERT新增 UPDATE修改 DELETE删除 GRANT授权 EXPORT导出 IMPORT导入 FORCE强退 GENCODE生成代码 CLEAN清空数据
:param log_type: 日志类型login表示登录日志operation表示为操作日志
:return:
"""
self.title = title
self.business_type = business_type.value
self.log_type = log_type
def __call__(self, func):
@wraps(func)
async def wrapper(*args, **kwargs):
start_time = time.time()
# 获取被装饰函数的文件路径
file_path = inspect.getfile(func)
# 获取项目根路径
project_root = os.getcwd()
# 处理文件路径,去除项目根路径部分
relative_path = os.path.relpath(file_path, start=project_root)[0:-2].replace('\\', '.').replace('/', '.')
# 获取当前被装饰函数所在路径
func_path = f'{relative_path}{func.__name__}()'
# 获取上下文信息
request_name_list = get_function_parameters_name_by_type(func, Request)
request = get_function_parameters_value_by_name(func, request_name_list[0], *args, **kwargs)
token = request.headers.get('Authorization')
session_name_list = get_function_parameters_name_by_type(func, AsyncSession)
query_db = get_function_parameters_value_by_name(func, session_name_list[0], *args, **kwargs)
request_method = request.method
operator_type = 0
user_agent = request.headers.get('User-Agent')
if 'Windows' in user_agent or 'Macintosh' in user_agent or 'Linux' in user_agent:
operator_type = 1
if 'Mobile' in user_agent or 'Android' in user_agent or 'iPhone' in user_agent:
operator_type = 2
# 获取请求的url
oper_url = request.url.path
# 获取请求的ip及ip归属区域
oper_ip = request.headers.get('X-Forwarded-For')
oper_location = '内网IP'
if AppConfig.app_ip_location_query:
oper_location = get_ip_location(oper_ip)
# 根据不同的请求类型使用不同的方法获取请求参数
content_type = request.headers.get('Content-Type')
if content_type and (
'multipart/form-data' in content_type or 'application/x-www-form-urlencoded' in content_type
):
payload = await request.form()
oper_param = '\n'.join([f'{key}: {value}' for key, value in payload.items()])
else:
payload = await request.body()
# 通过 request.path_params 直接访问路径参数
path_params = request.path_params
oper_param = {}
if payload:
oper_param.update(json.loads(str(payload, 'utf-8')))
if path_params:
oper_param.update(path_params)
oper_param = json.dumps(oper_param, ensure_ascii=False)
# 日志表请求参数字段长度最大为2000因此在此处判断长度
if len(oper_param) > 2000:
oper_param = '请求参数过长'
# 获取操作时间
oper_time = datetime.now()
# 此处在登录之前向原始函数传递一些登录信息,用于监测在线用户的相关信息
login_log = {}
if self.log_type == 'login':
user_agent_info = parse(user_agent)
browser = f'{user_agent_info.browser.family}'
system_os = f'{user_agent_info.os.family}'
if user_agent_info.browser.version != ():
browser += f' {user_agent_info.browser.version[0]}'
if user_agent_info.os.version != ():
system_os += f' {user_agent_info.os.version[0]}'
login_log = dict(
ipaddr=oper_ip,
loginLocation=oper_location,
browser=browser,
os=system_os,
loginTime=oper_time.strftime('%Y-%m-%d %H:%M:%S'),
)
kwargs['form_data'].login_info = login_log
try:
# 调用原始函数
result = await func(*args, **kwargs)
except (LoginException, ServiceWarning) as e:
logger.warning(e.message)
result = ResponseUtil.failure(data=e.data, msg=e.message)
except ServiceException as e:
logger.error(e.message)
result = ResponseUtil.error(data=e.data, msg=e.message)
except Exception as e:
logger.exception(e)
result = ResponseUtil.error(msg=str(e))
# 获取请求耗时
cost_time = float(time.time() - start_time) * 100
# 判断请求是否来自api文档
request_from_swagger = (
request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
)
request_from_redoc = (
request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
)
# 根据响应结果的类型使用不同的方法获取响应结果参数
if (
isinstance(result, JSONResponse)
or isinstance(result, ORJSONResponse)
or isinstance(result, UJSONResponse)
):
result_dict = json.loads(str(result.body, 'utf-8'))
else:
if request_from_swagger or request_from_redoc:
result_dict = {}
else:
if result.status_code == 200:
result_dict = {'code': result.status_code, 'message': '获取成功'}
else:
result_dict = {'code': result.status_code, 'message': '获取失败'}
json_result = json.dumps(result_dict, ensure_ascii=False)
# 根据响应结果获取响应状态及异常信息
status = 1
error_msg = ''
if result_dict.get('code') == 200:
status = 0
else:
error_msg = result_dict.get('msg')
# 根据日志类型向对应的日志表插入数据
if self.log_type == 'login':
# 登录请求来自于api文档时不记录登录日志其余情况则记录
if request_from_swagger or request_from_redoc:
pass
else:
user = kwargs.get('form_data')
user_name = user.username
login_log['loginTime'] = oper_time
login_log['userName'] = user_name
login_log['status'] = str(status)
login_log['msg'] = result_dict.get('msg')
await LoginLogService.add_login_log_services(query_db, LogininforModel(**login_log))
else:
try:
current_user = await LoginService.get_current_user(request, token, query_db)
oper_name = current_user.user.user_name if current_user.user else None
dept_name = current_user.user.dept.dept_name if current_user.user.dept else None
except:
oper_name = None
dept_name = None
operation_log = OperLogModel(
title=self.title,
businessType=self.business_type,
method=func_path,
requestMethod=request_method,
operatorType=operator_type,
operName=oper_name,
deptName=dept_name,
operUrl=oper_url,
operIp=oper_ip,
operLocation=oper_location,
operParam=oper_param,
jsonResult=json_result,
status=status,
errorMsg=error_msg,
operTime=oper_time,
costTime=int(cost_time),
)
await OperationLogService.add_operation_log_services(query_db, operation_log)
return result
return wrapper
@lru_cache()
def get_ip_location(oper_ip: str):
"""
查询ip归属区域
:param oper_ip: 需要查询的ip
:return: ip归属区域
"""
oper_location = '内网IP'
try:
if oper_ip != '127.0.0.1' and oper_ip != 'localhost':
oper_location = '未知'
ip_result = requests.get(f'https://qifu-api.baidubce.com/ip/geo/v1/district?ip={oper_ip}')
if ip_result.status_code == 200:
prov = ip_result.json().get('data').get('prov')
city = ip_result.json().get('data').get('city')
if prov or city:
oper_location = f'{prov}-{city}'
except Exception as e:
oper_location = '未知'
print(e)
return oper_location
def get_function_parameters_name_by_type(func: Callable, param_type: Any):
"""
获取函数指定类型的参数名称
:param func: 函数
:param arg_type: 参数类型
:return: 函数指定类型的参数名称
"""
# 获取函数的参数信息
parameters = inspect.signature(func).parameters
# 找到指定类型的参数名称
parameters_name_list = []
for name, param in parameters.items():
if param.annotation == param_type:
parameters_name_list.append(name)
return parameters_name_list
def get_function_parameters_value_by_name(func: Callable, name: str, *args, **kwargs):
"""
获取函数指定参数的值
:param func: 函数
:param name: 参数名
:return: 参数值
"""
# 获取参数值
bound_parameters = inspect.signature(func).bind(*args, **kwargs)
bound_parameters.apply_defaults()
parameters_value = bound_parameters.arguments.get(name)
return parameters_value

View File

@ -1,84 +0,0 @@
import inspect
from fastapi import Form, Query
from pydantic import BaseModel
from pydantic.fields import FieldInfo
from typing import Type, TypeVar
BaseModelVar = TypeVar('BaseModelVar', bound=BaseModel)
def as_query(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
"""
pydantic模型查询参数装饰器将pydantic模型用于接收查询参数
"""
new_parameters = []
for field_name, model_field in cls.model_fields.items():
model_field: FieldInfo # type: ignore
if not model_field.is_required():
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Query(default=model_field.default, description=model_field.description),
annotation=model_field.annotation,
)
)
else:
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Query(..., description=model_field.description),
annotation=model_field.annotation,
)
)
async def as_query_func(**data):
return cls(**data)
sig = inspect.signature(as_query_func)
sig = sig.replace(parameters=new_parameters)
as_query_func.__signature__ = sig # type: ignore
setattr(cls, 'as_query', as_query_func)
return cls
def as_form(cls: Type[BaseModelVar]) -> Type[BaseModelVar]:
"""
pydantic模型表单参数装饰器将pydantic模型用于接收表单参数
"""
new_parameters = []
for field_name, model_field in cls.model_fields.items():
model_field: FieldInfo # type: ignore
if not model_field.is_required():
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Form(default=model_field.default, description=model_field.description),
annotation=model_field.annotation,
)
)
else:
new_parameters.append(
inspect.Parameter(
model_field.alias,
inspect.Parameter.POSITIONAL_ONLY,
default=Form(..., description=model_field.description),
annotation=model_field.annotation,
)
)
async def as_form_func(**data):
return cls(**data)
sig = inspect.signature(as_form_func)
sig = sig.replace(parameters=new_parameters)
as_form_func.__signature__ = sig # type: ignore
setattr(cls, 'as_form', as_form_func)
return cls

View File

@ -1,75 +0,0 @@
from fastapi import Depends
from typing import Optional
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
class GetDataScope:
"""
获取当前用户数据权限对应的查询sql语句
"""
DATA_SCOPE_ALL = '1'
DATA_SCOPE_CUSTOM = '2'
DATA_SCOPE_DEPT = '3'
DATA_SCOPE_DEPT_AND_CHILD = '4'
DATA_SCOPE_SELF = '5'
def __init__(
self,
query_alias: Optional[str] = '',
db_alias: Optional[str] = 'db',
user_alias: Optional[str] = 'user_id',
dept_alias: Optional[str] = 'dept_id',
):
"""
获取当前用户数据权限对应的查询sql语句
:param query_alias: 所要查询表对应的sqlalchemy模型名称默认为''
:param db_alias: orm对象别名默认为'db'
:param user_alias: 用户id字段别名默认为'user_id'
:param dept_alias: 部门id字段别名默认为'dept_id'
"""
self.query_alias = query_alias
self.db_alias = db_alias
self.user_alias = user_alias
self.dept_alias = dept_alias
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
user_id = current_user.user.user_id
dept_id = current_user.user.dept_id
custom_data_scope_role_id_list = [
item.role_id for item in current_user.user.role if item.data_scope == self.DATA_SCOPE_CUSTOM
]
param_sql_list = []
for role in current_user.user.role:
if current_user.user.admin or role.data_scope == self.DATA_SCOPE_ALL:
param_sql_list = ['1 == 1']
break
elif role.data_scope == self.DATA_SCOPE_CUSTOM:
if len(custom_data_scope_role_id_list) > 1:
param_sql_list.append(
f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id.in_({custom_data_scope_role_id_list}))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
)
else:
param_sql_list.append(
f"{self.query_alias}.{self.dept_alias}.in_(select(SysRoleDept.dept_id).where(SysRoleDept.role_id == {role.role_id})) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
)
elif role.data_scope == self.DATA_SCOPE_DEPT:
param_sql_list.append(
f"{self.query_alias}.{self.dept_alias} == {dept_id} if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
)
elif role.data_scope == self.DATA_SCOPE_DEPT_AND_CHILD:
param_sql_list.append(
f"{self.query_alias}.{self.dept_alias}.in_(select(SysDept.dept_id).where(or_(SysDept.dept_id == {dept_id}, func.find_in_set({dept_id}, SysDept.ancestors)))) if hasattr({self.query_alias}, '{self.dept_alias}') else 1 == 0"
)
elif role.data_scope == self.DATA_SCOPE_SELF:
param_sql_list.append(
f"{self.query_alias}.{self.user_alias} == {user_id} if hasattr({self.query_alias}, '{self.user_alias}') else 1 == 0"
)
else:
param_sql_list.append('1 == 0')
param_sql_list = list(dict.fromkeys(param_sql_list))
param_sql = f"or_({', '.join(param_sql_list)})"
return param_sql

View File

@ -1,68 +0,0 @@
from fastapi import Depends
from typing import List, Union
from exceptions.exception import PermissionException
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
class CheckUserInterfaceAuth:
"""
校验当前用户是否具有相应的接口权限
"""
def __init__(self, perm: Union[str, List], is_strict: bool = False):
"""
校验当前用户是否具有相应的接口权限
:param perm: 权限标识
:param is_strict: 当传入的权限标识是list类型时是否开启严格模式开启表示会校验列表中的每一个权限标识所有的校验结果都需要为True才会通过
"""
self.perm = perm
self.is_strict = is_strict
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
user_auth_list = current_user.permissions
if '*:*:*' in user_auth_list:
return True
if isinstance(self.perm, str):
if self.perm in user_auth_list:
return True
if isinstance(self.perm, list):
if self.is_strict:
if all([perm_str in user_auth_list for perm_str in self.perm]):
return True
else:
if any([perm_str in user_auth_list for perm_str in self.perm]):
return True
raise PermissionException(data='', message='该用户无此接口权限')
class CheckRoleInterfaceAuth:
"""
根据角色校验当前用户是否具有相应的接口权限
"""
def __init__(self, role_key: Union[str, List], is_strict: bool = False):
"""
根据角色校验当前用户是否具有相应的接口权限
:param role_key: 角色标识
:param is_strict: 当传入的角色标识是list类型时是否开启严格模式开启表示会校验列表中的每一个角色标识所有的校验结果都需要为True才会通过
"""
self.role_key = role_key
self.is_strict = is_strict
def __call__(self, current_user: CurrentUserModel = Depends(LoginService.get_current_user)):
user_role_list = current_user.user.role
user_role_key_list = [role.role_key for role in user_role_list]
if isinstance(self.role_key, str):
if self.role_key in user_role_key_list:
return True
if isinstance(self.role_key, list):
if self.is_strict:
if all([role_key_str in user_role_key_list for role_key_str in self.role_key]):
return True
else:
if any([role_key_str in user_role_key_list for role_key_str in self.role_key]):
return True
raise PermissionException(data='', message='该用户无此接口权限')

View File

@ -1,89 +0,0 @@
from fastapi import APIRouter, Depends, Request
from typing import List
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
from module_admin.service.cache_service import CacheService
from module_admin.service.login_service import LoginService
from utils.log_util import logger
from utils.response_util import ResponseUtil
cacheController = APIRouter(prefix='/monitor/cache', dependencies=[Depends(LoginService.get_current_user)])
@cacheController.get(
'', response_model=CacheMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
)
async def get_monitor_cache_info(request: Request):
# 获取全量数据
cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request)
logger.info('获取成功')
return ResponseUtil.success(data=cache_info_query_result)
@cacheController.get(
'/getNames',
response_model=List[CacheInfoModel],
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
)
async def get_monitor_cache_name(request: Request):
# 获取全量数据
cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services()
logger.info('获取成功')
return ResponseUtil.success(data=cache_name_list_result)
@cacheController.get(
'/getKeys/{cache_name}',
response_model=List[str],
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
)
async def get_monitor_cache_key(request: Request, cache_name: str):
# 获取全量数据
cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name)
logger.info('获取成功')
return ResponseUtil.success(data=cache_key_list_result)
@cacheController.get(
'/getValue/{cache_name}/{cache_key}',
response_model=CacheInfoModel,
dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))],
)
async def get_monitor_cache_value(request: Request, cache_name: str, cache_key: str):
# 获取全量数据
cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key)
logger.info('获取成功')
return ResponseUtil.success(data=cache_value_list_result)
@cacheController.delete(
'/clearCacheName/{cache_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
)
async def clear_monitor_cache_name(request: Request, cache_name: str):
clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name)
logger.info(clear_cache_name_result.message)
return ResponseUtil.success(msg=clear_cache_name_result.message)
@cacheController.delete(
'/clearCacheKey/{cache_key}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))]
)
async def clear_monitor_cache_key(request: Request, cache_key: str):
clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key)
logger.info(clear_cache_key_result.message)
return ResponseUtil.success(msg=clear_cache_key_result.message)
@cacheController.delete('/clearCacheAll', dependencies=[Depends(CheckUserInterfaceAuth('monitor:cache:list'))])
async def clear_monitor_cache_all(request: Request):
clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request)
logger.info(clear_cache_all_result.message)
return ResponseUtil.success(msg=clear_cache_all_result.message)

View File

@ -1,40 +0,0 @@
import uuid
from datetime import timedelta
from fastapi import APIRouter, Request
from config.enums import RedisInitKeyConfig
from module_admin.entity.vo.login_vo import CaptchaCode
from module_admin.service.captcha_service import CaptchaService
from utils.response_util import ResponseUtil
from utils.log_util import logger
captchaController = APIRouter()
@captchaController.get('/captchaImage')
async def get_captcha_image(request: Request):
captcha_enabled = (
True
if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled')
== 'true'
else False
)
register_enabled = (
True
if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true'
else False
)
session_id = str(uuid.uuid4())
captcha_result = await CaptchaService.create_captcha_image_service()
image = captcha_result[0]
computed_result = captcha_result[1]
await request.app.state.redis.set(
f'{RedisInitKeyConfig.CAPTCHA_CODES.key}:{session_id}', computed_result, ex=timedelta(minutes=2)
)
logger.info(f'编号为{session_id}的会话获取图片验证码成功')
return ResponseUtil.success(
model_content=CaptchaCode(
captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id
)
)

View File

@ -1,36 +0,0 @@
from fastapi import APIRouter, BackgroundTasks, Depends, File, Query, Request, UploadFile
from module_admin.service.common_service import CommonService
from module_admin.service.login_service import LoginService
from utils.log_util import logger
from utils.response_util import ResponseUtil
commonController = APIRouter(prefix='/common', dependencies=[Depends(LoginService.get_current_user)])
@commonController.post('/upload')
async def common_upload(request: Request, file: UploadFile = File(...)):
upload_result = await CommonService.upload_service(request, file)
logger.info('上传成功')
return ResponseUtil.success(model_content=upload_result.result)
@commonController.get('/download')
async def common_download(
request: Request,
background_tasks: BackgroundTasks,
file_name: str = Query(alias='fileName'),
delete: bool = Query(),
):
download_result = await CommonService.download_services(background_tasks, file_name, delete)
logger.info(download_result.message)
return ResponseUtil.streaming(data=download_result.result)
@commonController.get('/download/resource')
async def common_download_resource(request: Request, resource: str = Query()):
download_resource_result = await CommonService.download_resource_services(resource)
logger.info(download_resource_result.message)
return ResponseUtil.streaming(data=download_resource_result.result)

View File

@ -1,58 +0,0 @@
from fastapi import APIRouter, Depends, Form, Request, Body, UploadFile, File
from module_admin.service.login_service import LoginService
from module_admin.annotation.log_annotation import Log
from module_admin.service.compreface_service import ComprefaceService
from config.enums import BusinessType
from utils.response_util import ResponseUtil
from utils.log_util import logger
import datetime
comprefaceController = APIRouter(prefix='/system/compreface'
, dependencies=[Depends(LoginService.get_current_user)]
)
# 人脸检测
@comprefaceController.post('/face_detection')
async def face_detection(request: Request, file: UploadFile = File(None)) -> dict:
"""
人脸检测
"""
if file: # 说明是表单上传
image = await file.read()
else: # 尝试按字节流读取
image = await request.body()
result = await ComprefaceService.face_detection_service(image)
print(result)
return ResponseUtil.success(data=result)
# 人脸识别
@comprefaceController.post('/face_recognition')
# @Log(title='人脸识别', business_type=BusinessType.OTHER)
async def face_recognition(request: Request, file: UploadFile = File(None)) -> dict:
"""
人脸识别
"""
if file: # 说明是表单上传
image = await file.read()
else: # 尝试按字节流读取
image = await request.body()
result = await ComprefaceService.face_recognition_service(image)
print(result)
return ResponseUtil.success(data=result)
# def my_job():
# print("任务执行时间:", datetime.datetime.now())
# from config.get_scheduler import scheduler
# from apscheduler.triggers.cron import CronTrigger
# trigger = CronTrigger(minute='*', second=0)
# scheduler.add_job(my_job, trigger=trigger)

View File

@ -1,123 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.config_service import ConfigService
from module_admin.service.login_service import LoginService
from utils.common_util import bytes2file_response, export_list2excel
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
configController = APIRouter(prefix='/system/config', dependencies=[Depends(LoginService.get_current_user)])
@configController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:list'))]
)
async def get_system_config_list(
request: Request,
config_page_query: ConfigPageQueryModel = Depends(ConfigPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=config_page_query_result)
@configController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:add'))])
@ValidateFields(validate_model='add_config')
@Log(title='参数管理', business_type=BusinessType.INSERT)
async def add_system_config(
request: Request,
add_config: ConfigModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_config.create_by = current_user.user.user_name
add_config.create_time = datetime.now()
add_config.update_by = current_user.user.user_name
add_config.update_time = datetime.now()
add_config_result = await ConfigService.add_config_services(request, query_db, add_config)
logger.info(add_config_result.message)
return ResponseUtil.success(msg=add_config_result.message)
@configController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:config:edit'))])
@ValidateFields(validate_model='edit_config')
@Log(title='参数管理', business_type=BusinessType.UPDATE)
async def edit_system_config(
request: Request,
edit_config: ConfigModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_config.update_by = current_user.user.user_name
edit_config.update_time = datetime.now()
edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config)
logger.info(edit_config_result.message)
return ResponseUtil.success(msg=edit_config_result.message)
@configController.delete('/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))])
@Log(title='参数管理', business_type=BusinessType.UPDATE)
async def refresh_system_config(request: Request, query_db: AsyncSession = Depends(get_db)):
refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db)
logger.info(refresh_config_result.message)
return ResponseUtil.success(msg=refresh_config_result.message)
@configController.delete('/{config_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:config:remove'))])
@Log(title='参数管理', business_type=BusinessType.DELETE)
async def delete_system_config(request: Request, config_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_config = DeleteConfigModel(configIds=config_ids)
delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config)
logger.info(delete_config_result.message)
return ResponseUtil.success(msg=delete_config_result.message)
@configController.get(
'/{config_id}', response_model=ConfigModel, dependencies=[Depends(CheckUserInterfaceAuth('system:config:query'))]
)
async def query_detail_system_config(request: Request, config_id: int, query_db: AsyncSession = Depends(get_db)):
config_detail_result = await ConfigService.config_detail_services(query_db, config_id)
logger.info(f'获取config_id为{config_id}的信息成功')
return ResponseUtil.success(data=config_detail_result)
@configController.get('/configKey/{config_key}')
async def query_system_config(request: Request, config_key: str):
# 获取全量数据
config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key)
logger.info('获取成功')
return ResponseUtil.success(msg=config_query_result)
@configController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:config:export'))])
@Log(title='参数管理', business_type=BusinessType.EXPORT)
async def export_system_config_list(
request: Request,
config_page_query: ConfigPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False)
config_export_result = await ConfigService.export_config_list_services(config_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=export_list2excel(config_export_result))

View File

@ -1,132 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.data_scope import GetDataScope
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.dept_service import DeptService
from module_admin.service.login_service import LoginService
from utils.log_util import logger
from utils.response_util import ResponseUtil
deptController = APIRouter(prefix='/system/dept', dependencies=[Depends(LoginService.get_current_user)])
@deptController.get(
'/list/exclude/{dept_id}',
response_model=List[DeptModel],
dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))],
)
async def get_system_dept_tree_for_edit_option(
request: Request,
dept_id: int,
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
dept_query = DeptModel(deptId=dept_id)
dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@deptController.get(
'/list', response_model=List[DeptModel], dependencies=[Depends(CheckUserInterfaceAuth('system:dept:list'))]
)
async def get_system_dept_list(
request: Request,
dept_query: DeptQueryModel = Depends(DeptQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@deptController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:add'))])
@ValidateFields(validate_model='add_dept')
@Log(title='部门管理', business_type=BusinessType.INSERT)
async def add_system_dept(
request: Request,
add_dept: DeptModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_dept.create_by = current_user.user.user_name
add_dept.create_time = datetime.now()
add_dept.update_by = current_user.user.user_name
add_dept.update_time = datetime.now()
add_dept_result = await DeptService.add_dept_services(query_db, add_dept)
logger.info(add_dept_result.message)
return ResponseUtil.success(data=add_dept_result)
@deptController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:edit'))])
@ValidateFields(validate_model='edit_dept')
@Log(title='部门管理', business_type=BusinessType.UPDATE)
async def edit_system_dept(
request: Request,
edit_dept: DeptModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql)
edit_dept.update_by = current_user.user.user_name
edit_dept.update_time = datetime.now()
edit_dept_result = await DeptService.edit_dept_services(query_db, edit_dept)
logger.info(edit_dept_result.message)
return ResponseUtil.success(msg=edit_dept_result.message)
@deptController.delete('/{dept_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dept:remove'))])
@Log(title='部门管理', business_type=BusinessType.DELETE)
async def delete_system_dept(
request: Request,
dept_ids: str,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
dept_id_list = dept_ids.split(',') if dept_ids else []
if dept_id_list:
for dept_id in dept_id_list:
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, int(dept_id), data_scope_sql)
delete_dept = DeleteDeptModel(deptIds=dept_ids)
delete_dept.update_by = current_user.user.user_name
delete_dept.update_time = datetime.now()
delete_dept_result = await DeptService.delete_dept_services(query_db, delete_dept)
logger.info(delete_dept_result.message)
return ResponseUtil.success(msg=delete_dept_result.message)
@deptController.get(
'/{dept_id}', response_model=DeptModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dept:query'))]
)
async def query_detail_system_dept(
request: Request,
dept_id: int,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql)
detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id)
logger.info(f'获取dept_id为{dept_id}的信息成功')
return ResponseUtil.success(data=detail_dept_result)

View File

@ -1,239 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.dict_vo import (
DeleteDictDataModel,
DeleteDictTypeModel,
DictDataModel,
DictDataPageQueryModel,
DictTypeModel,
DictTypePageQueryModel,
)
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.dict_service import DictDataService, DictTypeService
from module_admin.service.login_service import LoginService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
dictController = APIRouter(prefix='/system/dict', dependencies=[Depends(LoginService.get_current_user)])
@dictController.get(
'/type/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]
)
async def get_system_dict_type_list(
request: Request,
dict_type_page_query: DictTypePageQueryModel = Depends(DictTypePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(
query_db, dict_type_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=dict_type_page_query_result)
@dictController.post('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))])
@ValidateFields(validate_model='add_dict_type')
@Log(title='字典类型', business_type=BusinessType.INSERT)
async def add_system_dict_type(
request: Request,
add_dict_type: DictTypeModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_dict_type.create_by = current_user.user.user_name
add_dict_type.create_time = datetime.now()
add_dict_type.update_by = current_user.user.user_name
add_dict_type.update_time = datetime.now()
add_dict_type_result = await DictTypeService.add_dict_type_services(request, query_db, add_dict_type)
logger.info(add_dict_type_result.message)
return ResponseUtil.success(msg=add_dict_type_result.message)
@dictController.put('/type', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))])
@ValidateFields(validate_model='edit_dict_type')
@Log(title='字典类型', business_type=BusinessType.UPDATE)
async def edit_system_dict_type(
request: Request,
edit_dict_type: DictTypeModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_dict_type.update_by = current_user.user.user_name
edit_dict_type.update_time = datetime.now()
edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type)
logger.info(edit_dict_type_result.message)
return ResponseUtil.success(msg=edit_dict_type_result.message)
@dictController.delete('/type/refreshCache', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
@Log(title='字典类型', business_type=BusinessType.UPDATE)
async def refresh_system_dict(request: Request, query_db: AsyncSession = Depends(get_db)):
refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db)
logger.info(refresh_dict_result.message)
return ResponseUtil.success(msg=refresh_dict_result.message)
@dictController.delete('/type/{dict_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
@Log(title='字典类型', business_type=BusinessType.DELETE)
async def delete_system_dict_type(request: Request, dict_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids)
delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type)
logger.info(delete_dict_type_result.message)
return ResponseUtil.success(msg=delete_dict_type_result.message)
@dictController.get('/type/optionselect', response_model=List[DictTypeModel])
async def query_system_dict_type_options(request: Request, query_db: AsyncSession = Depends(get_db)):
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
query_db, DictTypePageQueryModel(**dict()), is_page=False
)
logger.info('获取成功')
return ResponseUtil.success(data=dict_type_query_result)
@dictController.get(
'/type/{dict_id}', response_model=DictTypeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))]
)
async def query_detail_system_dict_type(request: Request, dict_id: int, query_db: AsyncSession = Depends(get_db)):
dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id)
logger.info(f'获取dict_id为{dict_id}的信息成功')
return ResponseUtil.success(data=dict_type_detail_result)
@dictController.post('/type/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))])
@Log(title='字典类型', business_type=BusinessType.EXPORT)
async def export_system_dict_type_list(
request: Request,
dict_type_page_query: DictTypePageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
query_db, dict_type_page_query, is_page=False
)
dict_type_export_result = await DictTypeService.export_dict_type_list_services(dict_type_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result))
@dictController.get('/data/type/{dict_type}')
async def query_system_dict_type_data(request: Request, dict_type: str, query_db: AsyncSession = Depends(get_db)):
# 获取全量数据
dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(
request.app.state.redis, dict_type
)
logger.info('获取成功')
return ResponseUtil.success(data=dict_data_query_result)
@dictController.get(
'/data/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:dict:list'))]
)
async def get_system_dict_data_list(
request: Request,
dict_data_page_query: DictDataPageQueryModel = Depends(DictDataPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
dict_data_page_query_result = await DictDataService.get_dict_data_list_services(
query_db, dict_data_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=dict_data_page_query_result)
@dictController.post('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:add'))])
@ValidateFields(validate_model='add_dict_data')
@Log(title='字典数据', business_type=BusinessType.INSERT)
async def add_system_dict_data(
request: Request,
add_dict_data: DictDataModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_dict_data.create_by = current_user.user.user_name
add_dict_data.create_time = datetime.now()
add_dict_data.update_by = current_user.user.user_name
add_dict_data.update_time = datetime.now()
add_dict_data_result = await DictDataService.add_dict_data_services(request, query_db, add_dict_data)
logger.info(add_dict_data_result.message)
return ResponseUtil.success(msg=add_dict_data_result.message)
@dictController.put('/data', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:edit'))])
@ValidateFields(validate_model='edit_dict_data')
@Log(title='字典数据', business_type=BusinessType.UPDATE)
async def edit_system_dict_data(
request: Request,
edit_dict_data: DictDataModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_dict_data.update_by = current_user.user.user_name
edit_dict_data.update_time = datetime.now()
edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data)
logger.info(edit_dict_data_result.message)
return ResponseUtil.success(msg=edit_dict_data_result.message)
@dictController.delete('/data/{dict_codes}', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:remove'))])
@Log(title='字典数据', business_type=BusinessType.DELETE)
async def delete_system_dict_data(request: Request, dict_codes: str, query_db: AsyncSession = Depends(get_db)):
delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes)
delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data)
logger.info(delete_dict_data_result.message)
return ResponseUtil.success(msg=delete_dict_data_result.message)
@dictController.get(
'/data/{dict_code}',
response_model=DictDataModel,
dependencies=[Depends(CheckUserInterfaceAuth('system:dict:query'))],
)
async def query_detail_system_dict_data(request: Request, dict_code: int, query_db: AsyncSession = Depends(get_db)):
detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code)
logger.info(f'获取dict_code为{dict_code}的信息成功')
return ResponseUtil.success(data=detail_dict_data_result)
@dictController.post('/data/export', dependencies=[Depends(CheckUserInterfaceAuth('system:dict:export'))])
@Log(title='字典数据', business_type=BusinessType.EXPORT)
async def export_system_dict_data_list(
request: Request,
dict_data_page_query: DictDataPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
dict_data_query_result = await DictDataService.get_dict_data_list_services(
query_db, dict_data_page_query, is_page=False
)
dict_data_export_result = await DictDataService.export_dict_data_list_services(dict_data_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(dict_data_export_result))

View File

@ -1,162 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request, Body
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.door_service import DoorService
from module_admin.service.haikang_service import HaiKangService
from module_admin.entity.vo.door_vo import DeleteDoorModel, DoorModel, DoorPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
import time
doorController = APIRouter(prefix='/system/door', dependencies=[Depends(LoginService.get_current_user)])
"""
实时监控页面权限 access:monitor:view ,dependencies=[Depends(CheckUserInterfaceAuth('access:monitor:view'))]
识别记录表权限 access:record:list , dependencies=[Depends(CheckUserInterfaceAuth('access:record:list'))]
门禁设备管理 access:device:list, dependencies=[Depends(CheckUserInterfaceAuth('access:device:list'))]
"""
# 机器人控制开门
@doorController.post('/control_door')
async def control_door(request: Request, door_index_code: str = Body(), control_type: int = Body()):
print("door_index_code: ", door_index_code)
print("control_type: ", control_type)
start_time = time.time()
result = await HaiKangService.door_do_control_service(door_index_code, control_type)
print("end_time: ", time.time() - start_time)
if result[0]:
logger.info('门控制成功')
return ResponseUtil.success(data=result[1])
logger.error('门控制失败')
return ResponseUtil.error(msg=result[1])
# 获取门禁设备列表
@doorController.get(
'/list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('system:door:list'))]
, dependencies=[Depends(CheckUserInterfaceAuth('access:device:list'))]
)
async def get_system_door_list(
request: Request,
door_page_query: DoorPageQueryModel = Depends(DoorPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
door_page_query_result = await DoorService.get_door_list_services(query_db, door_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=door_page_query_result)
# 添加门禁设备
@doorController.post('/add'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:door:add'))]
, dependencies=[Depends(CheckUserInterfaceAuth('access:device:list'))]
)
@ValidateFields(validate_model='add_door')
@Log(title='门禁设备', business_type=BusinessType.INSERT)
async def add_system_door(
request: Request,
add_door: DoorModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_door.create_time = datetime.now()
add_door.create_by = current_user.user.user_name
add_door.update_time = datetime.now()
add_door.update_by = current_user.user.user_name
add_door_result = await DoorService.add_door_services(query_db, add_door)
logger.info(add_door_result.message)
return ResponseUtil.success(msg=add_door_result.message)
@doorController.put('/edit'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:door:edit'))]
, dependencies=[Depends(CheckUserInterfaceAuth('access:device:list'))]
)
@ValidateFields(validate_model='edit_door')
@Log(title='门禁设备', business_type=BusinessType.UPDATE)
async def edit_system_door(
request: Request,
edit_door: DoorModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_door.update_by = current_user.user.user_name
edit_door.update_time = datetime.now()
edit_door_result = await DoorService.edit_door_services(query_db, edit_door)
logger.info(edit_door_result.message)
return ResponseUtil.success(msg=edit_door_result.message)
@doorController.delete('/{ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:door:remove'))]
, dependencies=[Depends(CheckUserInterfaceAuth('access:device:list'))]
)
@Log(title='门禁设备', business_type=BusinessType.DELETE)
async def delete_system_door(request: Request, ids: str, query_db: AsyncSession = Depends(get_db)):
delete_door = DeleteDoorModel(ids=ids)
delete_door_result = await DoorService.delete_door_services(query_db, delete_door)
logger.info(delete_door_result.message)
return ResponseUtil.success(msg=delete_door_result.message)
# 获取设备状态
@doorController.get('/door_status', dependencies=[Depends(CheckUserInterfaceAuth('access:monitor:view'))])
async def get_door_status(request: Request, query_db: AsyncSession = Depends(get_db)):
result = await DoorService.get_door_status_service(query_db)
if result[0]:
return ResponseUtil.success(data=result[1])
return ResponseUtil.error(msg=result[1])
# 获取视频流地址
@doorController.get('/video_uri/{robot_id}' ,dependencies=[Depends(CheckUserInterfaceAuth('access:monitor:view'))])
async def get_video_uri(request: Request
, robot_id: int
, query_db: AsyncSession = Depends(get_db)
):
result = await DoorService.get_video_uri_service(robot_id, query_db)
return ResponseUtil.success(data=result)
# @doorController.get(
# '/{id}', response_model=DoorModel, dependencies=[Depends(CheckUserInterfaceAuth('system:door:query'))]
# )
# async def query_detail_system_door(request: Request, id: int, query_db: AsyncSession = Depends(get_db)):
# door_detail_result = await DoorService.door_detail_services(query_db, id)
# logger.info(f'获取id为{id}的信息成功')
# return ResponseUtil.success(data=door_detail_result)
# @doorController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:door:export'))])
# @Log(title='门禁设备', business_type=BusinessType.EXPORT)
# async def export_system_door_list(
# request: Request,
# door_page_query: DoorPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# door_query_result = await DoorService.get_door_list_services(query_db, door_page_query, is_page=False)
# door_export_result = await DoorService.export_door_list_services(door_query_result)
# logger.info('导出成功')
# return ResponseUtil.streaming(data=bytes2file_response(door_export_result))

View File

@ -1,143 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.explanation_content_type_vo import Explanation_content_typePageQueryModel, \
Explanation_content_typeQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.explanation_content_type_service import Explanation_content_typeService
from module_admin.service.login_service import LoginService
from module_admin.service.explanation_content_service import Explanation_contentService
from module_admin.entity.vo.explanation_content_vo import DeleteExplanation_contentModel, Explanation_contentModel, Explanation_contentPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
from config.enums import ExplanationContentStatus
explanationContentController = APIRouter(prefix='/system/explanation_content', dependencies=[Depends(LoginService.get_current_user)])
"""
展厅讲解权限字符 exhibitionhall:guide:query, dependencies=[Depends(CheckUserInterfaceAuth('exhibitionhall:guide:query'))]
"""
@explanationContentController.get(
'/list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:list'))]
)
async def get_system_explanation_content_list(
request: Request,
explanation_content_page_query: Explanation_contentPageQueryModel = Depends(Explanation_contentPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
explanation_content_page_query_result = await Explanation_contentService.get_explanation_content_list_services(query_db, explanation_content_page_query, is_page=False)
logger.info('获取成功')
return ResponseUtil.success(data=explanation_content_page_query_result)
@explanationContentController.post('/add_explanation'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:add'))]
)
@ValidateFields(validate_model='add_explanation_content')
@Log(title='讲解内容', business_type=BusinessType.INSERT)
async def add_system_explanation_content(
request: Request,
add_explanation_content: Explanation_contentModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_explanation_content.create_time = datetime.now()
add_explanation_content.create_by = current_user.user.user_name
add_explanation_content.update_time = datetime.now()
add_explanation_content.update_by = current_user.user.user_name
# 新添加内容状态默认0
add_explanation_content.status = ExplanationContentStatus.NOTSTART.value
add_explanation_content_result = await Explanation_contentService.add_explanation_content_services(query_db, add_explanation_content)
logger.info(add_explanation_content_result.message)
return ResponseUtil.success(msg=add_explanation_content_result.message)
@explanationContentController.put('/edit_explanation'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:edit'))]
)
@ValidateFields(validate_model='edit_explanation_content')
@Log(title='讲解内容', business_type=BusinessType.UPDATE)
async def edit_system_explanation_content(
request: Request,
edit_explanation_content: Explanation_contentModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_explanation_content.update_by = current_user.user.user_name
edit_explanation_content.update_time = datetime.now()
edit_explanation_content_result = await Explanation_contentService.edit_explanation_content_services(query_db, edit_explanation_content)
logger.info(edit_explanation_content_result.message)
return ResponseUtil.success(msg=edit_explanation_content_result.message)
@explanationContentController.delete('/{explanation_content_ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:remove'))]
)
@Log(title='讲解内容', business_type=BusinessType.DELETE)
async def delete_system_explanation_content(request: Request, explanation_content_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_explanation_content = DeleteExplanation_contentModel(explanationContentIds=explanation_content_ids)
delete_explanation_content_result = await Explanation_contentService.delete_explanation_content_services(query_db, delete_explanation_content)
logger.info(delete_explanation_content_result.message)
return ResponseUtil.success(msg=delete_explanation_content_result.message)
@explanationContentController.get(
'/type_list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:list'))]
)
async def get_system_explanation_content_type_list(
request: Request,
# explanation_content_type_page_query: Explanation_content_typePageQueryModel = Depends(Explanation_content_typePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
# explanation_content_type_page_query_result = await Explanation_content_typeService.get_explanation_content_type_list_services(query_db, explanation_content_type_page_query, is_page=True)
explanation_content_type_query_result = await Explanation_content_typeService.get_explanation_content_type_list_services(query_db, Explanation_content_typeQueryModel(), is_page=False)
logger.info('获取成功')
return ResponseUtil.success(data=explanation_content_type_query_result)
# @explanationContentController.get(
# '/{explanation_content_id}', response_model=Explanation_contentModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:query'))]
# )
# async def query_detail_system_explanation_content(request: Request, explanation_content_id: int, query_db: AsyncSession = Depends(get_db)):
# explanation_content_detail_result = await Explanation_contentService.explanation_content_detail_services(query_db, explanation_content_id)
# logger.info(f'获取explanation_content_id为{explanation_content_id}的信息成功')
#
# return ResponseUtil.success(data=explanation_content_detail_result)
# @explanationContentController.post('/export'
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content:export'))]
# )
# @Log(title='讲解内容', business_type=BusinessType.EXPORT)
# async def export_system_explanation_content_list(
# request: Request,
# explanation_content_page_query: Explanation_contentPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# explanation_content_query_result = await Explanation_contentService.get_explanation_content_list_services(query_db, explanation_content_page_query, is_page=False)
# explanation_content_export_result = await Explanation_contentService.export_explanation_content_list_services(explanation_content_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(explanation_content_export_result))

View File

@ -1,111 +0,0 @@
# from datetime import datetime
# from fastapi import APIRouter, Depends, Form, Request
# from pydantic_validation_decorator import ValidateFields
# from sqlalchemy.ext.asyncio import AsyncSession
# from config.enums import BusinessType
# from config.get_db import get_db
# from module_admin.annotation.log_annotation import Log
# from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
# from module_admin.entity.vo.user_vo import CurrentUserModel
# from module_admin.service.login_service import LoginService
# from module_admin.service.explanation_content_type_service import Explanation_content_typeService
# from module_admin.entity.vo.explanation_content_type_vo import DeleteExplanation_content_typeModel, Explanation_content_typeModel, Explanation_content_typePageQueryModel
# from utils.common_util import bytes2file_response
# from utils.log_util import logger
# from utils.page_util import PageResponseModel
# from utils.response_util import ResponseUtil
# explanation_content_typeController = APIRouter(prefix='/system/explanation_content_type'
# , dependencies=[Depends(LoginService.get_current_user)]
# )
#
#
# @explanation_content_typeController.get(
# '/list', response_model=PageResponseModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:list'))]
# )
# async def get_system_explanation_content_type_list(
# request: Request,
# # explanation_content_type_page_query: Explanation_content_typePageQueryModel = Depends(Explanation_content_typePageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# # explanation_content_type_page_query_result = await Explanation_content_typeService.get_explanation_content_type_list_services(query_db, explanation_content_type_page_query, is_page=True)
#
# explanation_content_type_query_result = await Explanation_content_typeService.get_explanation_content_type_list_services(query_db, is_page=False)
#
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=explanation_content_type_query_result)
# @explanation_content_typeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:add'))])
# @ValidateFields(validate_model='add_explanation_content_type')
# @Log(title='讲解内容类型', business_type=BusinessType.INSERT)
# async def add_system_explanation_content_type(
# request: Request,
# add_explanation_content_type: Explanation_content_typeModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_explanation_content_type.create_time = datetime.now()
# add_explanation_content_type.create_by = current_user.user.user_name
# add_explanation_content_type.update_time = datetime.now()
# add_explanation_content_type.update_by = current_user.user.user_name
# add_explanation_content_type_result = await Explanation_content_typeService.add_explanation_content_type_services(query_db, add_explanation_content_type)
# logger.info(add_explanation_content_type_result.message)
#
# return ResponseUtil.success(msg=add_explanation_content_type_result.message)
#
#
# @explanation_content_typeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:edit'))])
# @ValidateFields(validate_model='edit_explanation_content_type')
# @Log(title='讲解内容类型', business_type=BusinessType.UPDATE)
# async def edit_system_explanation_content_type(
# request: Request,
# edit_explanation_content_type: Explanation_content_typeModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_explanation_content_type.update_by = current_user.user.user_name
# edit_explanation_content_type.update_time = datetime.now()
# edit_explanation_content_type_result = await Explanation_content_typeService.edit_explanation_content_type_services(query_db, edit_explanation_content_type)
# logger.info(edit_explanation_content_type_result.message)
#
# return ResponseUtil.success(msg=edit_explanation_content_type_result.message)
#
#
# @explanation_content_typeController.delete('/{content_type_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:remove'))])
# @Log(title='讲解内容类型', business_type=BusinessType.DELETE)
# async def delete_system_explanation_content_type(request: Request, content_type_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_explanation_content_type = DeleteExplanation_content_typeModel(contentTypeIds=content_type_ids)
# delete_explanation_content_type_result = await Explanation_content_typeService.delete_explanation_content_type_services(query_db, delete_explanation_content_type)
# logger.info(delete_explanation_content_type_result.message)
#
# return ResponseUtil.success(msg=delete_explanation_content_type_result.message)
#
#
# @explanation_content_typeController.get(
# '/{content_type_id}', response_model=Explanation_content_typeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:query'))]
# )
# async def query_detail_system_explanation_content_type(request: Request, content_type_id: int, query_db: AsyncSession = Depends(get_db)):
# explanation_content_type_detail_result = await Explanation_content_typeService.explanation_content_type_detail_services(query_db, content_type_id)
# logger.info(f'获取content_type_id为{content_type_id}的信息成功')
#
# return ResponseUtil.success(data=explanation_content_type_detail_result)
#
#
# @explanation_content_typeController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_content_type:export'))])
# @Log(title='讲解内容类型', business_type=BusinessType.EXPORT)
# async def export_system_explanation_content_type_list(
# request: Request,
# explanation_content_type_page_query: Explanation_content_typePageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# explanation_content_type_query_result = await Explanation_content_typeService.get_explanation_content_type_list_services(query_db, explanation_content_type_page_query, is_page=False)
# explanation_content_type_export_result = await Explanation_content_typeService.export_explanation_content_type_list_services(explanation_content_type_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(explanation_content_type_export_result))

View File

@ -1,105 +0,0 @@
# from datetime import datetime
# from fastapi import APIRouter, Depends, Form, Request
# from pydantic_validation_decorator import ValidateFields
# from sqlalchemy.ext.asyncio import AsyncSession
# from config.enums import BusinessType
# from config.get_db import get_db
# from module_admin.annotation.log_annotation import Log
# from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
# from module_admin.entity.vo.user_vo import CurrentUserModel
# from module_admin.service.login_service import LoginService
# from module_admin.service.explanation_style_service import Explanation_styleService
# from module_admin.entity.vo.explanation_style_vo import DeleteExplanation_styleModel, Explanation_styleModel, Explanation_stylePageQueryModel
# from utils.common_util import bytes2file_response
# from utils.log_util import logger
# from utils.page_util import PageResponseModel
# from utils.response_util import ResponseUtil
#
#
# explanation_styleController = APIRouter(prefix='/system/explanation_style', dependencies=[Depends(LoginService.get_current_user)])
#
#
# @explanation_styleController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:list'))]
# )
# async def get_system_explanation_style_list(
# request: Request,
# explanation_style_page_query: Explanation_stylePageQueryModel = Depends(Explanation_stylePageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# explanation_style_page_query_result = await Explanation_styleService.get_explanation_style_list_services(query_db, explanation_style_page_query, is_page=True)
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=explanation_style_page_query_result)
#
#
# @explanation_styleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:add'))])
# @ValidateFields(validate_model='add_explanation_style')
# @Log(title='讲解风格', business_type=BusinessType.INSERT)
# async def add_system_explanation_style(
# request: Request,
# add_explanation_style: Explanation_styleModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_explanation_style.create_time = datetime.now()
# add_explanation_style.create_by = current_user.user.user_name
# add_explanation_style.update_time = datetime.now()
# add_explanation_style.update_by = current_user.user.user_name
# add_explanation_style_result = await Explanation_styleService.add_explanation_style_services(query_db, add_explanation_style)
# logger.info(add_explanation_style_result.message)
#
# return ResponseUtil.success(msg=add_explanation_style_result.message)
#
#
# @explanation_styleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:edit'))])
# @ValidateFields(validate_model='edit_explanation_style')
# @Log(title='讲解风格', business_type=BusinessType.UPDATE)
# async def edit_system_explanation_style(
# request: Request,
# edit_explanation_style: Explanation_styleModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_explanation_style.update_by = current_user.user.user_name
# edit_explanation_style.update_time = datetime.now()
# edit_explanation_style_result = await Explanation_styleService.edit_explanation_style_services(query_db, edit_explanation_style)
# logger.info(edit_explanation_style_result.message)
#
# return ResponseUtil.success(msg=edit_explanation_style_result.message)
#
#
# @explanation_styleController.delete('/{explanation_style_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:remove'))])
# @Log(title='讲解风格', business_type=BusinessType.DELETE)
# async def delete_system_explanation_style(request: Request, explanation_style_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_explanation_style = DeleteExplanation_styleModel(explanationStyleIds=explanation_style_ids)
# delete_explanation_style_result = await Explanation_styleService.delete_explanation_style_services(query_db, delete_explanation_style)
# logger.info(delete_explanation_style_result.message)
#
# return ResponseUtil.success(msg=delete_explanation_style_result.message)
#
#
# @explanation_styleController.get(
# '/{explanation_style_id}', response_model=Explanation_styleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:query'))]
# )
# async def query_detail_system_explanation_style(request: Request, explanation_style_id: int, query_db: AsyncSession = Depends(get_db)):
# explanation_style_detail_result = await Explanation_styleService.explanation_style_detail_services(query_db, explanation_style_id)
# logger.info(f'获取explanation_style_id为{explanation_style_id}的信息成功')
#
# return ResponseUtil.success(data=explanation_style_detail_result)
#
#
# @explanation_styleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style:export'))])
# @Log(title='讲解风格', business_type=BusinessType.EXPORT)
# async def export_system_explanation_style_list(
# request: Request,
# explanation_style_page_query: Explanation_stylePageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# explanation_style_query_result = await Explanation_styleService.get_explanation_style_list_services(query_db, explanation_style_page_query, is_page=False)
# explanation_style_export_result = await Explanation_styleService.export_explanation_style_list_services(explanation_style_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(explanation_style_export_result))

View File

@ -1,130 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.explanation_style_robot_pair_service import Explanation_style_robot_pairService
from module_admin.entity.vo.explanation_style_robot_pair_vo import DeleteExplanation_style_robot_pairModel, \
Explanation_style_robot_pairModel, Explanation_style_robot_pairPageQueryModel, SwitchExplanationStyleModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
explanation_style_robot_pairController = APIRouter(prefix='/system/explanation_style_robot_pair', dependencies=[Depends(LoginService.get_current_user)])
# @explanation_style_robot_pairController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:list'))]
# )
# async def get_system_explanation_style_robot_pair_list(
# request: Request,
# robot_id: int,
# # explanation_style_robot_pair_page_query: Explanation_style_robot_pairPageQueryModel = Depends(Explanation_style_robot_pairPageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# # explanation_style_robot_pair_page_query_result = await Explanation_style_robot_pairService.get_explanation_style_robot_pair_list_services(query_db, explanation_style_robot_pair_page_query, is_page=False)
# explanation_style_robot_pair_query_result = await Explanation_style_robot_pairService.get_style_robot_pair_list_services(query_db, robot_id)
# logger.info('获取成功')
# return ResponseUtil.success(data=explanation_style_robot_pair_query_result)
# 切换风格
@explanation_style_robot_pairController.post('/switch_style')
async def switch_explanation_style(
request: Request,
switch_explanation_style: SwitchExplanationStyleModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
switch_explanation_style.update_by = current_user.user.user_name
switch_explanation_style_message = await Explanation_style_robot_pairService.switch_explanation_style_services(query_db, switch_explanation_style)
if switch_explanation_style_message.is_success:
logger.info(switch_explanation_style_message.message)
return ResponseUtil.success(msg=switch_explanation_style_message.message)
else:
return ResponseUtil.error(msg=switch_explanation_style_message.message)
# @explanation_style_robot_pairController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:add'))])
# @ValidateFields(validate_model='add_explanation_style_robot_pair')
# @Log(title='讲解风格--机器人配对', business_type=BusinessType.INSERT)
# async def add_system_explanation_style_robot_pair(
# request: Request,
# add_explanation_style_robot_pair: Explanation_style_robot_pairModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_explanation_style_robot_pair.create_time = datetime.now()
# add_explanation_style_robot_pair.create_by = current_user.user.user_name
# add_explanation_style_robot_pair.update_time = datetime.now()
# add_explanation_style_robot_pair.update_by = current_user.user.user_name
# add_explanation_style_robot_pair_result = await Explanation_style_robot_pairService.add_explanation_style_robot_pair_services(query_db, add_explanation_style_robot_pair)
# logger.info(add_explanation_style_robot_pair_result.message)
#
# return ResponseUtil.success(msg=add_explanation_style_robot_pair_result.message)
# @explanation_style_robot_pairController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:edit'))])
# @ValidateFields(validate_model='edit_explanation_style_robot_pair')
# @Log(title='讲解风格--机器人配对', business_type=BusinessType.UPDATE)
# async def edit_system_explanation_style_robot_pair(
# request: Request,
# edit_explanation_style_robot_pair: Explanation_style_robot_pairModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_explanation_style_robot_pair.update_by = current_user.user.user_name
# edit_explanation_style_robot_pair.update_time = datetime.now()
# edit_explanation_style_robot_pair_result = await Explanation_style_robot_pairService.edit_explanation_style_robot_pair_services(query_db, edit_explanation_style_robot_pair)
# logger.info(edit_explanation_style_robot_pair_result.message)
#
# return ResponseUtil.success(msg=edit_explanation_style_robot_pair_result.message)
# @explanation_style_robot_pairController.delete('/{pairing_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:remove'))])
# @Log(title='讲解风格--机器人配对', business_type=BusinessType.DELETE)
# async def delete_system_explanation_style_robot_pair(request: Request, pairing_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_explanation_style_robot_pair = DeleteExplanation_style_robot_pairModel(pairingIds=pairing_ids)
# delete_explanation_style_robot_pair_result = await Explanation_style_robot_pairService.delete_explanation_style_robot_pair_services(query_db, delete_explanation_style_robot_pair)
# logger.info(delete_explanation_style_robot_pair_result.message)
#
# return ResponseUtil.success(msg=delete_explanation_style_robot_pair_result.message)
# @explanation_style_robot_pairController.get(
# '/{pairing_id}', response_model=Explanation_style_robot_pairModel, dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:query'))]
# )
# async def query_detail_system_explanation_style_robot_pair(request: Request, pairing_id: int, query_db: AsyncSession = Depends(get_db)):
# explanation_style_robot_pair_detail_result = await Explanation_style_robot_pairService.explanation_style_robot_pair_detail_services(query_db, pairing_id)
# logger.info(f'获取pairing_id为{pairing_id}的信息成功')
#
# return ResponseUtil.success(data=explanation_style_robot_pair_detail_result)
# @explanation_style_robot_pairController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:explanation_style_robot_pair:export'))])
# @Log(title='讲解风格--机器人配对', business_type=BusinessType.EXPORT)
# async def export_system_explanation_style_robot_pair_list(
# request: Request,
# explanation_style_robot_pair_page_query: Explanation_style_robot_pairPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# explanation_style_robot_pair_query_result = await Explanation_style_robot_pairService.get_explanation_style_robot_pair_list_services(query_db, explanation_style_robot_pair_page_query, is_page=False)
# explanation_style_robot_pair_export_result = await Explanation_style_robot_pairService.export_explanation_style_robot_pair_list_services(explanation_style_robot_pair_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(explanation_style_robot_pair_export_result))

View File

@ -1,81 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.service.login_service import LoginService
from module_admin.service.haikang_service import HaiKangService
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
from module_admin.entity.vo.haikang_vo import VisitorReservationQueryModel
from typing import List
haikang_controller = APIRouter(prefix="/system/haikang", dependencies=[Depends(LoginService.get_current_user)])
# # 查询门禁点列表
# @haikang_controller.get("/door_list"
# # , response_model=PageResponseModel
# # , dependencies=[Depends(CheckUserInterfaceAuth("system:haikang:list"))]
# )
# async def get_system_haikang_list(
# request: Request,
# pageNo:int,
# pageSize:int,
# ):
# """
# 查询门禁点列表
# """
# result = await HaiKangService.get_door_list_service(pageNo, pageSize)
# return parse_result(result)
# # 查询门禁点状态
# @haikang_controller.post(
# "/door_status",
# # dependencies=[Depends(CheckUserInterfaceAuth("system:haikang:list"))]
# )
# async def get_door_status(
# request: Request,
# door_index_codes: List[str],
# ):
# """
# 查询门禁点列表
# """
# result = await HaiKangService.get_door_status_service(door_index_codes)
# return parse_result(result)
# # 门禁点反控
# @haikang_controller.post(
# "/door_do_control",
# # dependencies=[Depends(CheckUserInterfaceAuth("system:haikang:list"))]
# )
# async def door_do_control(
# request: Request,
# door_index_codes: List[str],
# control_type: int,
# ):
# pass
# 查询访客预约记录
@haikang_controller.post(
"/get_visitor_list",
# dependencies=[Depends(CheckUserInterfaceAuth("system:haikang:list"))]
)
async def get_visitor(
request: Request,
visitor_query: VisitorReservationQueryModel
):
result = await HaiKangService.get_visitor_list_service(visitor_query)
return parse_result(result)
def parse_result(result):
if result[0]:
return ResponseUtil.success(data=result[1])
return ResponseUtil.error(msg=f"code:{result[1]} msg:{result[2]}")

View File

@ -1,106 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.identification_record_service import Identification_recordService
from module_admin.entity.vo.identification_record_vo import DeleteIdentification_recordModel, Identification_recordModel, Identification_recordPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
identification_recordController = APIRouter(prefix='/system/identification_record', dependencies=[Depends(LoginService.get_current_user)])
@identification_recordController.get(
'/list', response_model=PageResponseModel
, dependencies=[Depends(CheckUserInterfaceAuth('access:record:list'))]
)
async def get_system_identification_record_list(
request: Request,
identification_record_page_query: Identification_recordPageQueryModel = Depends(Identification_recordPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
identification_record_page_query_result = await Identification_recordService.get_identification_record_list_services(query_db, identification_record_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(data=identification_record_page_query_result)
@identification_recordController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_record:add'))])
@ValidateFields(validate_model='add_identification_record')
@Log(title='识别记录', business_type=BusinessType.INSERT)
async def add_system_identification_record(
request: Request,
add_identification_record: Identification_recordModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_identification_record.create_time = datetime.now()
add_identification_record.create_by = current_user.user.user_name
add_identification_record_result = await Identification_recordService.add_identification_record_services(query_db, add_identification_record)
logger.info(add_identification_record_result.message)
return ResponseUtil.success(msg=add_identification_record_result.message)
# @identification_recordController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_record:edit'))])
# @ValidateFields(validate_model='edit_identification_record')
# @Log(title='识别记录', business_type=BusinessType.UPDATE)
# async def edit_system_identification_record(
# request: Request,
# edit_identification_record: Identification_recordModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_identification_record.update_by = current_user.user.user_name
# edit_identification_record.update_time = datetime.now()
# edit_identification_record_result = await Identification_recordService.edit_identification_record_services(query_db, edit_identification_record)
# logger.info(edit_identification_record_result.message)
# return ResponseUtil.success(msg=edit_identification_record_result.message)
# @identification_recordController.delete('/{ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_record:remove'))])
# @Log(title='识别记录', business_type=BusinessType.DELETE)
# async def delete_system_identification_record(request: Request, ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_identification_record = DeleteIdentification_recordModel(ids=ids)
# delete_identification_record_result = await Identification_recordService.delete_identification_record_services(query_db, delete_identification_record)
# logger.info(delete_identification_record_result.message)
# return ResponseUtil.success(msg=delete_identification_record_result.message)
# @identification_recordController.get(
# '/{id}', response_model=Identification_recordModel, dependencies=[Depends(CheckUserInterfaceAuth('system:identification_record:query'))]
# )
# async def query_detail_system_identification_record(request: Request, id: int, query_db: AsyncSession = Depends(get_db)):
# identification_record_detail_result = await Identification_recordService.identification_record_detail_services(query_db, id)
# logger.info(f'获取id为{id}的信息成功')
# return ResponseUtil.success(data=identification_record_detail_result)
@identification_recordController.post('/export'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:identification_record:export'))]
)
@Log(title='识别记录', business_type=BusinessType.EXPORT)
async def export_system_identification_record_list(
request: Request,
identification_record_page_query: Identification_recordPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
identification_record_query_result = await Identification_recordService.get_identification_record_list_services(query_db, identification_record_page_query, is_page=False)
identification_record_export_result = await Identification_recordService.export_identification_record_list_services(identification_record_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(identification_record_export_result))

View File

@ -1,131 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.identification_statistics_service import Identification_statisticsService
from module_admin.entity.vo.identification_statistics_vo import DeleteIdentification_statisticsModel, Identification_statisticsModel, Identification_statisticsPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
identification_statisticsController = APIRouter(prefix='/system/identification_statistics', dependencies=[Depends(LoginService.get_current_user)])
# 获取今天的识别统计数据
@identification_statisticsController.get('/today')
async def get_today_identification_statistics(request: Request, query_db: AsyncSession = Depends(get_db)):
"""
获取今天的识别统计数据
:param request:
:param query_db:
:return:
"""
logger.info('获取今天的识别统计数据')
identification_statistics = await Identification_statisticsService.get_today_identification_statistics_services(query_db)
return ResponseUtil.success(data = identification_statistics)
# 获取总的识别统计数据
@identification_statisticsController.get('/total')
async def get_total_identification_statistics(request: Request, query_db: AsyncSession = Depends(get_db)):
"""
获取今天的识别统计数据
:param request:
:param query_db:
:return:
"""
logger.info('获取今天的识别统计数据')
identification_statistics = await Identification_statisticsService.get_total_identification_statistics_services(query_db)
return ResponseUtil.success(data = identification_statistics)
# @identification_statisticsController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:list'))]
# )
# async def get_system_identification_statistics_list(
# request: Request,
# identification_statistics_page_query: Identification_statisticsPageQueryModel = Depends(Identification_statisticsPageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# identification_statistics_page_query_result = await Identification_statisticsService.get_identification_statistics_list_services(query_db, identification_statistics_page_query, is_page=True)
# logger.info('获取成功')
# return ResponseUtil.success(model_content=identification_statistics_page_query_result)
# @identification_statisticsController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:add'))])
# @ValidateFields(validate_model='add_identification_statistics')
# @Log(title='识别统计', business_type=BusinessType.INSERT)
# async def add_system_identification_statistics(
# request: Request,
# add_identification_statistics: Identification_statisticsModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_identification_statistics.create_time = datetime.now()
# add_identification_statistics.create_by = current_user.user.user_name
# add_identification_statistics_result = await Identification_statisticsService.add_identification_statistics_services(query_db, add_identification_statistics)
# logger.info(add_identification_statistics_result.message)
# return ResponseUtil.success(msg=add_identification_statistics_result.message)
# @identification_statisticsController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:edit'))])
# @ValidateFields(validate_model='edit_identification_statistics')
# @Log(title='识别统计', business_type=BusinessType.UPDATE)
# async def edit_system_identification_statistics(
# request: Request,
# edit_identification_statistics: Identification_statisticsModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_identification_statistics.update_by = current_user.user.user_name
# edit_identification_statistics.update_time = datetime.now()
# edit_identification_statistics_result = await Identification_statisticsService.edit_identification_statistics_services(query_db, edit_identification_statistics)
# logger.info(edit_identification_statistics_result.message)
# return ResponseUtil.success(msg=edit_identification_statistics_result.message)
# @identification_statisticsController.delete('/{ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:remove'))])
# @Log(title='识别统计', business_type=BusinessType.DELETE)
# async def delete_system_identification_statistics(request: Request, ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_identification_statistics = DeleteIdentification_statisticsModel(ids=ids)
# delete_identification_statistics_result = await Identification_statisticsService.delete_identification_statistics_services(query_db, delete_identification_statistics)
# logger.info(delete_identification_statistics_result.message)
# return ResponseUtil.success(msg=delete_identification_statistics_result.message)
# @identification_statisticsController.get(
# '/{id}', response_model=Identification_statisticsModel, dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:query'))]
# )
# async def query_detail_system_identification_statistics(request: Request, id: int, query_db: AsyncSession = Depends(get_db)):
# identification_statistics_detail_result = await Identification_statisticsService.identification_statistics_detail_services(query_db, id)
# logger.info(f'获取id为{id}的信息成功')
# return ResponseUtil.success(data=identification_statistics_detail_result)
# @identification_statisticsController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:identification_statistics:export'))])
# @Log(title='识别统计', business_type=BusinessType.EXPORT)
# async def export_system_identification_statistics_list(
# request: Request,
# identification_statistics_page_query: Identification_statisticsPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# identification_statistics_query_result = await Identification_statisticsService.get_identification_statistics_list_services(query_db, identification_statistics_page_query, is_page=False)
# identification_statistics_export_result = await Identification_statisticsService.export_identification_statistics_list_services(identification_statistics_query_result)
# logger.info('导出成功')
# return ResponseUtil.streaming(data=bytes2file_response(identification_statistics_export_result))

View File

@ -1,131 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.info_service import InfoService
from module_admin.entity.vo.info_vo import DeleteInfoModel, InfoModel, InfoPageQueryModel, InfoUpdateModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
infoController = APIRouter(prefix='/robot/info', dependencies=[Depends(LoginService.get_current_user)])
@infoController.get(
'/list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('robot:info:list'))]
)
async def get_system_info_list(
request: Request,
info_page_query: InfoPageQueryModel = Depends(InfoPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
print('xxxxxxxxx', info_page_query.begin_create_time)
print('xxxxxxxxx',info_page_query.end_create_time)
print(info_page_query.name)
# 获取分页数据
info_page_query_result = await InfoService.get_info_list_services(query_db, info_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=info_page_query_result)
@infoController.post('/add_robot'
# , dependencies=[Depends(CheckUserInterfaceAuth('robot:info:add'))]
)
@ValidateFields(validate_model='add_info')
@Log(title='机器人信息', business_type=BusinessType.INSERT)
async def add_system_info(
request: Request,
add_info: InfoModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_info.create_time = datetime.now()
add_info.create_by = current_user.user.user_name
add_info.update_time = datetime.now()
add_info.update_by = current_user.user.user_name
add_info.del_flag = '0'
add_info.online = '1'
add_info.power = '100'
add_info_result = await InfoService.add_info_services(query_db, add_info)
logger.info(add_info_result.message)
return ResponseUtil.success(msg=add_info_result.message)
@infoController.put('/edit_robot'
# , dependencies=[Depends(CheckUserInterfaceAuth('robot:info:edit'))]
)
@ValidateFields(validate_model='edit_info')
@Log(title='机器人信息', business_type=BusinessType.UPDATE)
async def edit_system_info(
request: Request,
edit_info: InfoUpdateModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_info.update_by = current_user.user.user_name
edit_info.update_time = datetime.now()
edit_info_result = await InfoService.edit_info_services(query_db, edit_info)
logger.info(edit_info_result.message)
return ResponseUtil.success(msg=edit_info_result.message)
@infoController.delete('/{robot_ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('robot:info:remove'))]
)
@Log(title='机器人信息', business_type=BusinessType.DELETE)
async def delete_system_info(request: Request, robot_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_info = DeleteInfoModel(robotIds=robot_ids)
delete_info_result = await InfoService.delete_info_services(query_db, delete_info)
logger.info(delete_info_result.message)
return ResponseUtil.success(msg=delete_info_result.message)
@infoController.get(
'/{robot_id}', response_model=InfoModel
# , dependencies=[Depends(CheckUserInterfaceAuth('robot:info:query'))]
)
async def query_detail_system_info(request: Request, robot_id: int, query_db: AsyncSession = Depends(get_db)):
info_detail_result = await InfoService.info_detail_services(query_db, robot_id)
logger.info(f'获取robot_id为{robot_id}的信息成功')
return ResponseUtil.success(data=info_detail_result)
# 根据机器人id刷新机器人信息
@infoController.get('/refresh_robot/{robot_ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:info:add'))]
)
async def refresh_robot(request: Request,robot_ids: str , query_db: AsyncSession = Depends(get_db)):
refresh_result = await InfoService.refresh_robot_services(query_db, robot_ids)
logger.info(f'刷新机器人信息成功')
return ResponseUtil.success(data=refresh_result)
@infoController.post('/export'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:info:export'))]
)
@Log(title='机器人信息', business_type=BusinessType.EXPORT)
async def export_system_info_list(
request: Request,
info_page_query: InfoPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
info_query_result = await InfoService.get_info_list_services(query_db, info_page_query, is_page=False)
info_export_result = await InfoService.export_info_list_services(info_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(info_export_result))

View File

@ -1,194 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.job_vo import (
DeleteJobLogModel,
DeleteJobModel,
EditJobModel,
JobLogPageQueryModel,
JobModel,
JobPageQueryModel,
)
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.job_log_service import JobLogService
from module_admin.service.job_service import JobService
from module_admin.service.login_service import LoginService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
jobController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)])
@jobController.get(
'/job/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]
)
async def get_system_job_list(
request: Request,
job_page_query: JobPageQueryModel = Depends(JobPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
notice_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=notice_page_query_result)
@jobController.post('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:add'))])
@ValidateFields(validate_model='add_job')
@Log(title='定时任务', business_type=BusinessType.INSERT)
async def add_system_job(
request: Request,
add_job: JobModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_job.create_by = current_user.user.user_name
add_job.create_time = datetime.now()
add_job.update_by = current_user.user.user_name
add_job.update_time = datetime.now()
add_job_result = await JobService.add_job_services(query_db, add_job)
logger.info(add_job_result.message)
return ResponseUtil.success(msg=add_job_result.message)
@jobController.put('/job', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:edit'))])
@ValidateFields(validate_model='edit_job')
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def edit_system_job(
request: Request,
edit_job: EditJobModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_job.update_by = current_user.user.user_name
edit_job.update_time = datetime.now()
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
logger.info(edit_job_result.message)
return ResponseUtil.success(msg=edit_job_result.message)
@jobController.put('/job/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))])
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def change_system_job_status(
request: Request,
change_job: EditJobModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_job = EditJobModel(
jobId=change_job.job_id,
status=change_job.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
logger.info(edit_job_result.message)
return ResponseUtil.success(msg=edit_job_result.message)
@jobController.put('/job/run', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:changeStatus'))])
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def execute_system_job(request: Request, execute_job: JobModel, query_db: AsyncSession = Depends(get_db)):
execute_job_result = await JobService.execute_job_once_services(query_db, execute_job)
logger.info(execute_job_result.message)
return ResponseUtil.success(msg=execute_job_result.message)
@jobController.delete('/job/{job_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
@Log(title='定时任务', business_type=BusinessType.DELETE)
async def delete_system_job(request: Request, job_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_job = DeleteJobModel(jobIds=job_ids)
delete_job_result = await JobService.delete_job_services(query_db, delete_job)
logger.info(delete_job_result.message)
return ResponseUtil.success(msg=delete_job_result.message)
@jobController.get(
'/job/{job_id}', response_model=JobModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:query'))]
)
async def query_detail_system_job(request: Request, job_id: int, query_db: AsyncSession = Depends(get_db)):
job_detail_result = await JobService.job_detail_services(query_db, job_id)
logger.info(f'获取job_id为{job_id}的信息成功')
return ResponseUtil.success(data=job_detail_result)
@jobController.post('/job/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))])
@Log(title='定时任务', business_type=BusinessType.EXPORT)
async def export_system_job_list(
request: Request,
job_page_query: JobPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False)
job_export_result = await JobService.export_job_list_services(request, job_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(job_export_result))
@jobController.get(
'/jobLog/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:list'))]
)
async def get_system_job_log_list(
request: Request,
job_log_page_query: JobLogPageQueryModel = Depends(JobLogPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
job_log_page_query_result = await JobLogService.get_job_log_list_services(
query_db, job_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=job_log_page_query_result)
@jobController.delete('/jobLog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
@Log(title='定时任务调度日志', business_type=BusinessType.CLEAN)
async def clear_system_job_log(request: Request, query_db: AsyncSession = Depends(get_db)):
clear_job_log_result = await JobLogService.clear_job_log_services(query_db)
logger.info(clear_job_log_result.message)
return ResponseUtil.success(msg=clear_job_log_result.message)
@jobController.delete('/jobLog/{job_log_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:remove'))])
@Log(title='定时任务调度日志', business_type=BusinessType.DELETE)
async def delete_system_job_log(request: Request, job_log_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids)
delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log)
logger.info(delete_job_log_result.message)
return ResponseUtil.success(msg=delete_job_log_result.message)
@jobController.post('/jobLog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:job:export'))])
@Log(title='定时任务调度日志', business_type=BusinessType.EXPORT)
async def export_system_job_log_list(
request: Request,
job_log_page_query: JobLogPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False)
job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result))

View File

@ -1,150 +0,0 @@
from fastapi import APIRouter, Depends, Form, Request
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.log_vo import (
DeleteLoginLogModel,
DeleteOperLogModel,
LoginLogPageQueryModel,
OperLogPageQueryModel,
UnlockUser,
)
from module_admin.service.log_service import LoginLogService, OperationLogService
from module_admin.service.login_service import LoginService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
logController = APIRouter(prefix='/monitor', dependencies=[Depends(LoginService.get_current_user)])
@logController.get(
'/operlog/list',
response_model=PageResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:list'))],
)
async def get_system_operation_log_list(
request: Request,
operation_log_page_query: OperLogPageQueryModel = Depends(OperLogPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(
query_db, operation_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=operation_log_page_query_result)
@logController.delete('/operlog/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))])
@Log(title='操作日志', business_type=BusinessType.CLEAN)
async def clear_system_operation_log(request: Request, query_db: AsyncSession = Depends(get_db)):
clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db)
logger.info(clear_operation_log_result.message)
return ResponseUtil.success(msg=clear_operation_log_result.message)
@logController.delete('/operlog/{oper_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:remove'))])
@Log(title='操作日志', business_type=BusinessType.DELETE)
async def delete_system_operation_log(request: Request, oper_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_operation_log = DeleteOperLogModel(operIds=oper_ids)
delete_operation_log_result = await OperationLogService.delete_operation_log_services(
query_db, delete_operation_log
)
logger.info(delete_operation_log_result.message)
return ResponseUtil.success(msg=delete_operation_log_result.message)
@logController.post('/operlog/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:operlog:export'))])
@Log(title='操作日志', business_type=BusinessType.EXPORT)
async def export_system_operation_log_list(
request: Request,
operation_log_page_query: OperLogPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
operation_log_query_result = await OperationLogService.get_operation_log_list_services(
query_db, operation_log_page_query, is_page=False
)
operation_log_export_result = await OperationLogService.export_operation_log_list_services(
request, operation_log_query_result
)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result))
@logController.get(
'/logininfor/list',
response_model=PageResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:list'))],
)
async def get_system_login_log_list(
request: Request,
login_log_page_query: LoginLogPageQueryModel = Depends(LoginLogPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
login_log_page_query_result = await LoginLogService.get_login_log_list_services(
query_db, login_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=login_log_page_query_result)
@logController.delete('/logininfor/clean', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))])
@Log(title='登录日志', business_type=BusinessType.CLEAN)
async def clear_system_login_log(request: Request, query_db: AsyncSession = Depends(get_db)):
clear_login_log_result = await LoginLogService.clear_login_log_services(query_db)
logger.info(clear_login_log_result.message)
return ResponseUtil.success(msg=clear_login_log_result.message)
@logController.delete(
'/logininfor/{info_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:remove'))]
)
@Log(title='登录日志', business_type=BusinessType.DELETE)
async def delete_system_login_log(request: Request, info_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_login_log = DeleteLoginLogModel(infoIds=info_ids)
delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log)
logger.info(delete_login_log_result.message)
return ResponseUtil.success(msg=delete_login_log_result.message)
@logController.get(
'/logininfor/unlock/{user_name}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:unlock'))]
)
@Log(title='账户解锁', business_type=BusinessType.OTHER)
async def unlock_system_user(request: Request, user_name: str, query_db: AsyncSession = Depends(get_db)):
unlock_user = UnlockUser(userName=user_name)
unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user)
logger.info(unlock_user_result.message)
return ResponseUtil.success(msg=unlock_user_result.message)
@logController.post('/logininfor/export', dependencies=[Depends(CheckUserInterfaceAuth('monitor:logininfor:export'))])
@Log(title='登录日志', business_type=BusinessType.EXPORT)
async def export_system_login_log_list(
request: Request,
login_log_page_query: LoginLogPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
login_log_query_result = await LoginLogService.get_login_log_list_services(
query_db, login_log_page_query, is_page=False
)
login_log_export_result = await LoginLogService.export_login_log_list_services(login_log_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(login_log_export_result))

View File

@ -1,155 +0,0 @@
import jwt
import uuid
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Optional
from config.enums import BusinessType, RedisInitKeyConfig
from config.env import AppConfig, JwtConfig
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.login_vo import UserLogin, UserRegister, Token
from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel
from module_admin.service.login_service import CustomOAuth2PasswordRequestForm, LoginService, oauth2_scheme
from module_admin.service.user_service import UserService
from utils.log_util import logger
from utils.response_util import ResponseUtil
loginController = APIRouter()
@loginController.post('/login', response_model=Token)
@Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login')
async def login(
request: Request, form_data: CustomOAuth2PasswordRequestForm = Depends(), query_db: AsyncSession = Depends(get_db)
):
# 是否启用验证码
# captcha_enabled = (
# True
# if await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled')
# == 'true'
# else False
# )
captcha_enabled =False
user = UserLogin(
userName=form_data.username,
password=form_data.password,
code=form_data.code,
uuid=form_data.uuid,
loginInfo=form_data.login_info,
captchaEnabled=captcha_enabled,
)
result = await LoginService.authenticate_user(request, query_db, user)
access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes)
session_id = str(uuid.uuid4())
access_token = await LoginService.create_access_token(
data={
'user_id': str(result[0].user_id),
'user_name': result[0].user_name,
'dept_name': result[1].dept_name if result[1] else None,
'session_id': session_id,
'login_info': user.login_info,
},
expires_delta=access_token_expires,
)
if AppConfig.app_same_time_login:
await request.app.state.redis.set(
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{session_id}',
access_token,
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
)
else:
# 此方法可实现同一账号同一时间只能登录一次
await request.app.state.redis.set(
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{result[0].user_id}',
access_token,
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
)
await UserService.edit_user_services(
query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')
)
logger.info('登录成功')
# 判断请求是否来自于api文档如果是返回指定格式的结果用于修复api文档认证成功后token显示undefined的bug
request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
if request_from_swagger or request_from_redoc:
return {'access_token': access_token, 'token_type': 'Bearer'}
return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token})
@loginController.get('/getInfo', response_model=CurrentUserModel)
async def get_login_user_info(
request: Request, current_user: CurrentUserModel = Depends(LoginService.get_current_user)
):
logger.info('获取成功')
return ResponseUtil.success(model_content=current_user)
@loginController.get('/getRouters')
async def get_login_user_routers(
request: Request,
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
query_db: AsyncSession = Depends(get_db),
):
logger.info('获取成功')
user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db)
return ResponseUtil.success(data=user_routers)
@loginController.post('/register', response_model=CrudResponseModel)
async def register_user(request: Request, user_register: UserRegister, query_db: AsyncSession = Depends(get_db)):
user_register_result = await LoginService.register_user_services(request, query_db, user_register)
logger.info(user_register_result.message)
return ResponseUtil.success(data=user_register_result, msg=user_register_result.message)
# @loginController.post("/getSmsCode", response_model=SmsCode)
# async def get_sms_code(request: Request, user: ResetUserModel, query_db: AsyncSession = Depends(get_db)):
# try:
# sms_result = await LoginService.get_sms_code_services(request, query_db, user)
# if sms_result.is_success:
# logger.info('获取成功')
# return ResponseUtil.success(data=sms_result)
# else:
# logger.warning(sms_result.message)
# return ResponseUtil.failure(msg=sms_result.message)
# except Exception as e:
# logger.exception(e)
# return ResponseUtil.error(msg=str(e))
#
#
# @loginController.post("/forgetPwd", response_model=CrudResponseModel)
# async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: AsyncSession = Depends(get_db)):
# try:
# forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user)
# if forget_user_result.is_success:
# logger.info(forget_user_result.message)
# return ResponseUtil.success(data=forget_user_result, msg=forget_user_result.message)
# else:
# logger.warning(forget_user_result.message)
# return ResponseUtil.failure(msg=forget_user_result.message)
# except Exception as e:
# logger.exception(e)
# return ResponseUtil.error(msg=str(e))
@loginController.post('/logout')
async def logout(request: Request
# , token: Optional[str] = Depends(oauth2_scheme)
):
token = request.headers.get('Authorization').split(" ")[-1]
payload = jwt.decode(
token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}
)
session_id: str = payload.get('session_id')
await LoginService.logout_services(request, session_id)
logger.info('退出成功')
return ResponseUtil.success(msg='退出成功')

View File

@ -1,114 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from typing import List
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.menu_service import MenuService
from utils.log_util import logger
from utils.response_util import ResponseUtil
menuController = APIRouter(prefix='/system/menu', dependencies=[Depends(LoginService.get_current_user)])
@menuController.get('/treeselect')
async def get_system_menu_tree(
request: Request,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user)
logger.info('获取成功')
return ResponseUtil.success(data=menu_query_result)
@menuController.get('/roleMenuTreeselect/{role_id}')
async def get_system_role_menu_tree(
request: Request,
role_id: int,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_menu_query_result)
@menuController.get(
'/list', response_model=List[MenuModel], dependencies=[Depends(CheckUserInterfaceAuth('system:menu:list'))]
)
async def get_system_menu_list(
request: Request,
menu_query: MenuQueryModel = Depends(MenuQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user)
logger.info('获取成功')
return ResponseUtil.success(data=menu_query_result)
@menuController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:add'))])
@ValidateFields(validate_model='add_menu')
@Log(title='菜单管理', business_type=BusinessType.INSERT)
async def add_system_menu(
request: Request,
add_menu: MenuModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_menu.create_by = current_user.user.user_name
add_menu.create_time = datetime.now()
add_menu.update_by = current_user.user.user_name
add_menu.update_time = datetime.now()
add_menu_result = await MenuService.add_menu_services(query_db, add_menu)
logger.info(add_menu_result.message)
return ResponseUtil.success(msg=add_menu_result.message)
@menuController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:edit'))])
@ValidateFields(validate_model='edit_menu')
@Log(title='菜单管理', business_type=BusinessType.UPDATE)
async def edit_system_menu(
request: Request,
edit_menu: MenuModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_menu.update_by = current_user.user.user_name
edit_menu.update_time = datetime.now()
edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu)
logger.info(edit_menu_result.message)
return ResponseUtil.success(msg=edit_menu_result.message)
@menuController.delete('/{menu_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:menu:remove'))])
@Log(title='菜单管理', business_type=BusinessType.DELETE)
async def delete_system_menu(request: Request, menu_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_menu = DeleteMenuModel(menuIds=menu_ids)
delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu)
logger.info(delete_menu_result.message)
return ResponseUtil.success(msg=delete_menu_result.message)
@menuController.get(
'/{menu_id}', response_model=MenuModel, dependencies=[Depends(CheckUserInterfaceAuth('system:menu:query'))]
)
async def query_detail_system_menu(request: Request, menu_id: int, query_db: AsyncSession = Depends(get_db)):
menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id)
logger.info(f'获取menu_id为{menu_id}的信息成功')
return ResponseUtil.success(data=menu_detail_result)

View File

@ -1,163 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.message_service import MessageService
from module_admin.entity.vo.message_vo import DeleteMessageModel, MessageModel, MessagePageQueryModel, EditMessageModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
messageController = APIRouter(prefix='/system/message', dependencies=[Depends(LoginService.get_current_user)])
# 查看告警类型分布
@messageController.get(
'/alarm_type_distribution'
)
async def get_alarm_type_distribution(
request: Request,
query_db: AsyncSession = Depends(get_db),
):
result = await MessageService.get_alarm_type_distribution_services(query_db)
return ResponseUtil.success(data=result)
# 一键处理未处理的告警消息
@messageController.get(
'/handle_all'
)
async def handle_all_message(
query_db: AsyncSession = Depends(get_db),
):
result = await MessageService.handle_all_message_services(query_db)
return ResponseUtil.success(msg= result.message)
# 查询告警数量信息
@messageController.get(
'/count_message',
)
async def count_message(request: Request, query_db: AsyncSession = Depends(get_db)):
""""""
count_message_result = await MessageService.count_message(query_db)
return ResponseUtil.success(data = count_message_result)
# # 获取所有消息列表
# @messageController.get(
# '/list', response_model=PageResponseModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:message:list'))]
# )
# async def get_system_message_list(
# request: Request,
# message_page_query: MessagePageQueryModel = Depends(MessagePageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# message_page_query_result = await MessageService.get_message_list_services(query_db, message_page_query, is_page=True)
# logger.info('获取成功')
# return ResponseUtil.success(model_content=message_page_query_result)
# 获取告警消息列表
@messageController.get('/alert_message')
async def get_alert_message(
request: Request,
pageNum: int = 1,
pageSize: int = 10,
query_db: AsyncSession = Depends(get_db),
):
alert_message = await MessageService.get_alert_message_services(query_db, pageNum, pageSize)
return ResponseUtil.success(model_content=alert_message)
# 该接口只做测试用, 并不对外开放
# @messageController.post('/add_message'
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:message:add'))]
# )
# @ValidateFields(validate_model='add_message')
# @Log(title='系统消息', business_type=BusinessType.INSERT)
# async def add_system_message(
# request: Request,
# add_message: MessageModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_message.create_time = datetime.now()
# add_message.create_by = current_user.user.user_name
# add_message.update_time = datetime.now()
# add_message.update_by = current_user.user.user_name
# add_message.status = '0'
# add_message_result = await MessageService.add_message_services(query_db, add_message)
# logger.info(add_message_result.message)
# return ResponseUtil.success(msg=add_message_result.message)
# @messageController.put('/edit_message'
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:message:edit'))]
# )
# @ValidateFields(validate_model='edit_message')
# @Log(title='系统消息', business_type=BusinessType.UPDATE)
# async def edit_system_message(
# request: Request,
# edit_message: EditMessageModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_message.update_by = current_user.user.user_name
# edit_message.update_time = datetime.now()
# edit_message_result = await MessageService.edit_message_services(query_db, edit_message)
# logger.info(edit_message_result.message)
# return ResponseUtil.success(msg=edit_message_result.message)
# @messageController.delete('/{message_ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('system:message:remove'))]
# )
# @Log(title='系统消息', business_type=BusinessType.DELETE)
# async def delete_system_message(request: Request, message_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_message = DeleteMessageModel(messageIds=message_ids)
# delete_message_result = await MessageService.delete_message_services(query_db, delete_message)
# logger.info(delete_message_result.message)
# return ResponseUtil.success(msg=delete_message_result.message)
# @messageController.get(
# '/{message_id}', response_model=MessageModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:message:query'))]
# )
# async def query_detail_system_message(request: Request, message_id: int, query_db: AsyncSession = Depends(get_db)):
# message_detail_result = await MessageService.message_detail_services(query_db, message_id)
# logger.info(f'获取message_id为{message_id}的信息成功')
# return ResponseUtil.success(data=message_detail_result)
# @messageController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:message:export'))])
# @Log(title='系统消息', business_type=BusinessType.EXPORT)
# async def export_system_message_list(
# request: Request,
# message_page_query: MessagePageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# message_query_result = await MessageService.get_message_list_services(query_db, message_page_query, is_page=False)
# message_export_result = await MessageService.export_message_list_services(message_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(message_export_result))

View File

@ -1,89 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.notice_service import NoticeService
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
noticeController = APIRouter(prefix='/system/notice', dependencies=[Depends(LoginService.get_current_user)])
@noticeController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:list'))]
)
async def get_system_notice_list(
request: Request,
notice_page_query: NoticePageQueryModel = Depends(NoticePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=notice_page_query_result)
@noticeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:add'))])
@ValidateFields(validate_model='add_notice')
@Log(title='通知公告', business_type=BusinessType.INSERT)
async def add_system_notice(
request: Request,
add_notice: NoticeModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_notice.create_by = current_user.user.user_name
add_notice.create_time = datetime.now()
add_notice.update_by = current_user.user.user_name
add_notice.update_time = datetime.now()
add_notice_result = await NoticeService.add_notice_services(query_db, add_notice)
logger.info(add_notice_result.message)
return ResponseUtil.success(msg=add_notice_result.message)
@noticeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:edit'))])
@ValidateFields(validate_model='edit_notice')
@Log(title='通知公告', business_type=BusinessType.UPDATE)
async def edit_system_notice(
request: Request,
edit_notice: NoticeModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_notice.update_by = current_user.user.user_name
edit_notice.update_time = datetime.now()
edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice)
logger.info(edit_notice_result.message)
return ResponseUtil.success(msg=edit_notice_result.message)
@noticeController.delete('/{notice_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:notice:remove'))])
@Log(title='通知公告', business_type=BusinessType.DELETE)
async def delete_system_notice(request: Request, notice_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_notice = DeleteNoticeModel(noticeIds=notice_ids)
delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice)
logger.info(delete_notice_result.message)
return ResponseUtil.success(msg=delete_notice_result.message)
@noticeController.get(
'/{notice_id}', response_model=NoticeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:notice:query'))]
)
async def query_detail_system_post(request: Request, notice_id: int, query_db: AsyncSession = Depends(get_db)):
notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id)
logger.info(f'获取notice_id为{notice_id}的信息成功')
return ResponseUtil.success(data=notice_detail_result)

View File

@ -1,40 +0,0 @@
from fastapi import APIRouter, Depends, Request
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlineQueryModel
from module_admin.service.login_service import LoginService
from module_admin.service.online_service import OnlineService
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
onlineController = APIRouter(prefix='/monitor/online', dependencies=[Depends(LoginService.get_current_user)])
@onlineController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:list'))]
)
async def get_monitor_online_list(
request: Request, online_page_query: OnlineQueryModel = Depends(OnlineQueryModel.as_query)
):
# 获取全量数据
online_query_result = await OnlineService.get_online_list_services(request, online_page_query)
logger.info('获取成功')
return ResponseUtil.success(
model_content=PageResponseModel(rows=online_query_result, total=len(online_query_result))
)
@onlineController.delete('/{token_ids}', dependencies=[Depends(CheckUserInterfaceAuth('monitor:online:forceLogout'))])
@Log(title='在线用户', business_type=BusinessType.FORCE)
async def delete_monitor_online(request: Request, token_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_online = DeleteOnlineModel(tokenIds=token_ids)
delete_online_result = await OnlineService.delete_online_services(request, delete_online)
logger.info(delete_online_result.message)
return ResponseUtil.success(msg=delete_online_result.message)

View File

@ -1,105 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.service.login_service import LoginService
from module_admin.service.post_service import PostService
from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
postController = APIRouter(prefix='/system/post', dependencies=[Depends(LoginService.get_current_user)])
@postController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:list'))]
)
async def get_system_post_list(
request: Request,
post_page_query: PostPageQueryModel = Depends(PostPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=post_page_query_result)
@postController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:add'))])
@ValidateFields(validate_model='add_post')
@Log(title='岗位管理', business_type=BusinessType.INSERT)
async def add_system_post(
request: Request,
add_post: PostModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_post.create_by = current_user.user.user_name
add_post.create_time = datetime.now()
add_post.update_by = current_user.user.user_name
add_post.update_time = datetime.now()
add_post_result = await PostService.add_post_services(query_db, add_post)
logger.info(add_post_result.message)
return ResponseUtil.success(msg=add_post_result.message)
@postController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:post:edit'))])
@ValidateFields(validate_model='edit_post')
@Log(title='岗位管理', business_type=BusinessType.UPDATE)
async def edit_system_post(
request: Request,
edit_post: PostModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_post.update_by = current_user.user.user_name
edit_post.update_time = datetime.now()
edit_post_result = await PostService.edit_post_services(query_db, edit_post)
logger.info(edit_post_result.message)
return ResponseUtil.success(msg=edit_post_result.message)
@postController.delete('/{post_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:post:remove'))])
@Log(title='岗位管理', business_type=BusinessType.DELETE)
async def delete_system_post(request: Request, post_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_post = DeletePostModel(postIds=post_ids)
delete_post_result = await PostService.delete_post_services(query_db, delete_post)
logger.info(delete_post_result.message)
return ResponseUtil.success(msg=delete_post_result.message)
@postController.get(
'/{post_id}', response_model=PostModel, dependencies=[Depends(CheckUserInterfaceAuth('system:post:query'))]
)
async def query_detail_system_post(request: Request, post_id: int, query_db: AsyncSession = Depends(get_db)):
post_detail_result = await PostService.post_detail_services(query_db, post_id)
logger.info(f'获取post_id为{post_id}的信息成功')
return ResponseUtil.success(data=post_detail_result)
@postController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:post:export'))])
@Log(title='岗位管理', business_type=BusinessType.EXPORT)
async def export_system_post_list(
request: Request,
post_page_query: PostPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False)
post_export_result = await PostService.export_post_list_services(post_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(post_export_result))

View File

@ -1,630 +0,0 @@
"""
简化的RAGFlow控制器 - 集成语义缓存
"""
import asyncio
import hashlib
import json
import time
from typing import Any, AsyncGenerator, Dict, Generator, Tuple
from fastapi import APIRouter, Depends, Request
from fastapi.responses import StreamingResponse
from module_admin.service.login_service import LoginService
from module_admin.service.kb_es_service import KBESService
from module_admin.service.ragflow_service import RAGFlowService
from module_admin.service.search_service import SearchService
from module_admin.entity.vo.ragflow_vo import (
ConverseWithChatAssistantModel,
CreateSessionWithChatModel,
UpdateChatAssistantModel,
RagflowListQueryModel
)
from utils.log_util import logger
from utils.response_util import ResponseUtil
from utils.semantic_cache_service import get_semantic_cache_service, store_qa_pair, get_question_hash
from utils.static_qa_service import get_static_qa_service
from utils.deepseek_client import DeepSeekAPIClient
from config.env import KBConfig
async def _async_store_qa(chat_id: str, question: str, answer: str, redis) -> None:
"""
异步存储问答对到语义缓存
"""
store_hash = get_question_hash(question)
logger.info(f"[SemanticCache] 存储QA | chat_id={chat_id} | question={question} | hash={store_hash} | answer_length={len(answer)}")
try:
await store_qa_pair(chat_id, question, answer, redis)
except Exception as e:
logger.warning(f"[SemanticCache] 异步存储失败: {e}")
# 使用标准的APIRouter增加认证依赖
ragflowController = APIRouter(prefix="/system/ragflow", dependencies=[Depends(LoginService.get_current_user)])
def format_sse(data: dict, event: str | None = None) -> str:
"""格式化SSE数据"""
payload = json.dumps(data, ensure_ascii=False)
prefix = f'event: {event}\n' if event else ''
return f'{prefix}data: {payload}\n\n'
def parse_result(result: Dict[str, Any]) -> Dict[str, Any]:
"""统一结果解析"""
code = result.get('code', 0)
if code != 0:
msg = result.get('message') or result.get('msg') or '接口异常'
return ResponseUtil.error(msg=msg, data=result.get('data', None))
return ResponseUtil.success(data=result.get('data', None))
def build_chat_cache_key(chat_id: str, question: str) -> str:
"""构建聊天缓存键"""
digest = hashlib.sha256(question.encode('utf-8')).hexdigest()
return f'ragflow:chat:{chat_id}:{digest}'
def remove_style_hint(question: str) -> Tuple[str, bool]:
"""
移除语言风格提示词
Args:
question: 原始问题
Returns:
(处理后的问题, 是否移除了风格提示词)
"""
if not question:
return question, False
import re
pattern = r'语言风格\s*[:]\s*[^,。!?\n]*'
match = re.search(pattern, question)
if match:
style_hint = match.group(0)
cleaned_question = re.sub(pattern, '', question).strip()
cleaned_question = re.sub(r'\s+', ' ', cleaned_question)
logger.info(f'[StyleHint] 移除风格提示词: {style_hint} | 原始问题: {question} | 处理后: {cleaned_question}')
return cleaned_question, True
return question, False
# 非流式对话接口
@ragflowController.post('/converse_with_chat_assistant')
async def converse_with_chat_assistant(
request: Request,
converse_params: ConverseWithChatAssistantModel,
):
"""
与聊天助手进行对话 - 集成语义缓存版本支持流式和非流式
匹配流程
1. 移除语言风格提示词
2. 静态问答匹配 (threshold=0.70)
3. 搜索服务判断
4. RAG历史缓存匹配 (threshold=0.60)
5. RAG服务调用使用原始问题
"""
start_time = time.perf_counter()
original_question = converse_params.question
cleaned_question, style_removed = remove_style_hint(original_question)
if style_removed:
converse_params.question = cleaned_question
# 获取redis实例
redis = getattr(request.app.state, 'redis', None)
cached_answer = None
cache_similarity = 0.0
# ========== 1. 静态问答匹配 ==========
try:
static_qa_service = get_static_qa_service()
logger.info(f'[StaticQA] 开始匹配 | chat_id={converse_params.chat_id} | question={converse_params.question} | threshold=0.70')
static_match, static_sim = static_qa_service.find_match(converse_params.question, threshold=0.70)
logger.info(f'[StaticQA] 匹配结果 | similarity={static_sim:.2f} | matched={static_match is not None}')
if static_match:
cached_answer = static_match.get('answer', '')
cache_similarity = static_sim
logger.info(f'[RAG_SOURCE] 命中静态FAQ | chat_id={converse_params.chat_id} | question={converse_params.question} | similarity={cache_similarity:.2f} | answer_length={len(cached_answer)}')
logger.info(f'[StaticQA] 流式响应使用静态问答答案chat_id={converse_params.chat_id}')
return StreamingResponse(
stream_cached_response(cached_answer, converse_params.chat_id, start_time, cache_source='static_qa'),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
except Exception as e:
logger.warning(f'[StaticQA] 静态问答匹配失败: {e}')
# ========== 2. 检查是否应该使用搜索服务 ==========
try:
intent = await SearchService.classify_intent(converse_params.question)
logger.info(f"[RAG_PROFILE] Intent Router ({converse_params.chat_id}): {intent}")
if intent == 'SEARCH':
return await SearchService.handle_search_chat(converse_params, redis)
except Exception as e:
logger.warning(f"意图分类失败使用RAG服务: {e}")
# ========== 3. RAG历史缓存查找 ==========
# 注意:当 KB_PROVIDER=es_bm25 时内部KB答案应直接来源于 ES 检索结果,
# 避免 rag:semantic:cache 抢答导致“curl 与 API 不一致”。
if KBConfig.KB_PROVIDER != 'es_bm25':
logger.info(f'[SemanticCache] 准备执行RAG历史缓存查找 | redis={redis is not None} | chat_id={converse_params.chat_id}')
if redis:
lookup_hash = get_question_hash(converse_params.question)
logger.info(f'[SemanticCache] 开始查找 | chat_id={converse_params.chat_id} | question={converse_params.question} | hash={lookup_hash} | threshold=0.60')
service = get_semantic_cache_service()
logger.info(f'[SemanticCache] service实例: {service}')
cache_result = await service.lookup(
converse_params.chat_id,
converse_params.question,
redis
)
logger.info(f'[SemanticCache] 查找结果 | found={cache_result is not None}')
if cache_result:
cached_answer, cache_similarity = cache_result
logger.info(f'[RAG_SOURCE] 命中RAG会话历史 | chat_id={converse_params.chat_id} | question={converse_params.question} | similarity={cache_similarity:.2f} | answer_length={len(cached_answer)}')
logger.info(f'[SemanticCache] 流式响应使用RAG历史缓存答案chat_id={converse_params.chat_id}')
return StreamingResponse(
stream_cached_response(cached_answer, converse_params.chat_id, start_time, cache_source='rag_history'),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
else:
logger.info(f"[SemanticCache] skip lookup because KB_PROVIDER=es_bm25 | chat_id={converse_params.chat_id}")
# ========== 4. RAG服务调用在这里根据 KB_PROVIDER 选择 ragflow / es_bm25 ==========
try:
# 恢复原始问题(包含语言风格提示词)
if style_removed:
converse_params.question = original_question
logger.info(f'[StyleHint] 恢复原始问题: {original_question}')
if KBConfig.KB_PROVIDER == 'es_bm25':
try:
chunks, metrics = await KBESService.retrieve(converse_params.question, redis=redis)
logger.info(
f"[KB_ES] retrieve_ms={metrics.retrieve_ms:.1f} | top1_score={metrics.top1_score:.3f} | score_gap={metrics.score_gap:.3f} | "
f"hit_count={metrics.hit_count} | keyword_coverage={metrics.keyword_coverage:.2f} | cache_hit={metrics.cache_hit} | "
f"chat_id={converse_params.chat_id}"
)
if KBESService.is_confident(metrics):
# KB_PROVIDER=es_bm25 时不写入 rag:semantic:cache避免污染后续命中
cache_store_func = None
return StreamingResponse(
stream_kb_es_response(
question=converse_params.question,
chunks=chunks,
chat_id=converse_params.chat_id,
start_time=start_time,
cache_store_func=cache_store_func,
retrieve_ms=metrics.retrieve_ms,
),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
logger.info(
f"[KB_ES] 低置信度准备fallback | fallback={KBConfig.KB_FALLBACK} | chat_id={converse_params.chat_id}"
)
if KBConfig.KB_FALLBACK == 'none':
return StreamingResponse(
stream_cached_response(
'我目前不太确定答案。请补充更多关键词或换种问法。',
converse_params.chat_id,
start_time,
cache_source='kb_es_low_confidence'
),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
except Exception as e:
logger.warning(f"[KB_ES] 内部KB异常: {e}")
if KBConfig.KB_FALLBACK == 'none':
return StreamingResponse(
stream_cached_response(
'内部知识库检索失败,请稍后再试或补充更多关键词。',
converse_params.chat_id,
start_time,
cache_source='kb_es_error'
),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
logger.info(f'[RAG_SOURCE] 调用原生RAG服务 | chat_id={converse_params.chat_id} | question={converse_params.question}')
result = RAGFlowService.converse_with_chat_assistant_services(converse_params)
cache_question = cleaned_question if style_removed else converse_params.question
store_hash = get_question_hash(cache_question)
logger.info(f'[RAG_CACHE] 准备存储 | chat_id={converse_params.chat_id} | question={cache_question} | hash={store_hash}')
async def cache_store_func(answer: str):
if redis and answer and len(answer.strip()) >= 10:
try:
await _async_store_qa(converse_params.chat_id, cache_question, answer, redis)
logger.info(f'[RAG_CACHE] 语义缓存存储成功 | chat_id={converse_params.chat_id} | answer_length={len(answer)}')
except Exception as e:
logger.warning(f'[RAG_CACHE] 语义缓存存储失败: {e}')
return StreamingResponse(
stream_ragflow_response(result, converse_params.chat_id, start_time, cache_store_func=cache_store_func),
media_type='text/event-stream',
headers={
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'X-Accel-Buffering': 'no',
'Transfer-Encoding': 'chunked'
}
)
except Exception as e:
logger.exception(f'[RAG_PROFILE] ragflow对话异常: {e}')
return ResponseUtil.error(msg=f'对话服务异常: {str(e)}')
async def stream_ragflow_response(result: Generator, chat_id: str, start_time: float, cache_store_func=None) -> AsyncGenerator[str, None]:
"""
流式处理RAGFlow响应 - 异步版本修复首token延迟
"""
import time
server_stream_start = time.time()
logger.info(f"[RAG_SERVER {server_stream_start:.3f}] 🚀 开始流式响应处理chat_id: {chat_id}")
last_answer = ""
first_token_received = False
start_stream_time = time.perf_counter()
# 立即发送连接建立消息解决首token延迟
connection_time = time.time()
ping_message = "event: ping\ndata: {\"status\": \"connected\"}\n\n"
yield ping_message
logger.info(f"[RAG_SERVER {connection_time:.3f}] 📡 连接建立ping发送耗时: {connection_time - server_stream_start:.3f}s")
chunk_count = 0
try:
for chunk in result:
chunk_time = time.time()
chunk_count += 1
# 让出控制权,确保流式响应
await asyncio.sleep(0)
# 检查第一个token的延迟
if not first_token_received:
first_token_received = True
latency = time.perf_counter() - start_stream_time
logger.info(f"[RAG_SERVER {chunk_time:.3f}] 🎯 首token到达耗时: {latency:.3f}s")
# 处理chunk数据
payload = chunk.get('data') if isinstance(chunk, dict) else chunk
if not payload:
logger.info(f"[RAG_SERVER {chunk_time:.3f}] ⚠️ 空chunk跳过")
continue
body = payload if isinstance(payload, dict) else {'data': payload}
# 处理错误
if isinstance(chunk, dict) and chunk.get('code') and chunk.get('code') != 0:
logger.error(f"[RAG_SERVER {chunk_time:.3f}] ❌ RAGFlow Stream Error: {chunk}")
error_message = format_sse({'message': chunk.get('message', '流式处理异常')}, event='error')
yield error_message
continue
# 处理answer字段的增量更新
if isinstance(body, dict) and 'answer' in body:
current_answer = body['answer']
# 安全检查确保current_answer不为None且为字符串
if current_answer is None:
logger.warning(f"[RAG_SERVER {chunk_time:.3f}] ⚠️ current_answer为None跳过处理")
continue
if not isinstance(current_answer, str):
logger.warning(f"[RAG_SERVER {chunk_time:.3f}] ⚠️ current_answer不是字符串类型: {type(current_answer)}")
current_answer = str(current_answer)
# 计算增量内容
if current_answer.startswith(last_answer):
delta = current_answer[len(last_answer):]
if delta:
body['answer'] = delta
last_answer = current_answer
logger.info(f"[RAG_SERVER {chunk_time:.3f}] 📝 Chunk #{chunk_count} 处理完成delta长度: {len(delta)}")
yield format_sse(body)
else:
# 上下文重置的备用处理
last_answer = current_answer
logger.info(f"[RAG_SERVER {chunk_time:.3f}] 🔄 Chunk #{chunk_count} 上下文重置")
yield format_sse(body)
else:
logger.info(f"[RAG_SERVER {chunk_time:.3f}] 📦 Chunk #{chunk_count} 其他数据: {body}")
yield format_sse(body)
# 流结束
stream_end_time = time.time()
end_message = format_sse({'status': 'completed'}, event='end')
yield end_message
logger.info(f'[RAG_SERVER {stream_end_time:.3f}] 流式响应完成chat_id: {chat_id}')
logger.info(f'[RAG_SERVER {stream_end_time:.3f}] 总共处理chunk数量: {chunk_count}')
logger.info(f'[RAG_SOURCE] 原生RAG流式响应完成 | chat_id={chat_id} | total_chunks={chunk_count} | answer_length={len(last_answer)}')
except Exception as exc:
error_time = time.time()
logger.exception(f'[RAG_SERVER {error_time:.3f}] ragflow流式对话异常: {exc}')
error_message = format_sse({'message': str(exc)}, event='error')
yield error_message
finally:
total_time = time.perf_counter() - start_time
logger.info(f'[RAG_SERVER {time.time():.3f}] ⏱️ Total Stream Duration ({chat_id}): {total_time:.3f}s')
if cache_store_func and last_answer and len(last_answer.strip()) >= 10:
try:
await cache_store_func(last_answer)
logger.info(f'[RAG_CACHE] 缓存存储完成 | chat_id={chat_id} | answer_length={len(last_answer)}')
except Exception as cache_err:
logger.warning(f'[RAG_CACHE] 缓存存储失败: {cache_err}')
# 聊天助手列表
@ragflowController.post('/get_chat_assistant_list')
async def get_chat_assistant_list(
query_params: RagflowListQueryModel, # 使用正确的Pydantic模型
):
"""获取聊天助手列表"""
result = RAGFlowService.get_chat_assistant_list_services(query_params)
return parse_result(result)
# 创建会话
@ragflowController.post('/create_session_with_chat')
async def create_session_with_chat(
create_params: CreateSessionWithChatModel, # 使用正确的Pydantic模型
):
"""创建聊天会话"""
result = RAGFlowService.create_session_with_chat_services(create_params)
return parse_result(result)
# 更新聊天助手
@ragflowController.post('/update_chat_assistant')
async def update_chat_assistant(
update_params: UpdateChatAssistantModel, # 使用正确的Pydantic模型
):
"""更新聊天助手"""
result = RAGFlowService.update_chat_assistant_services(update_params)
return parse_result(result)
# 数据集相关接口
@ragflowController.post('/dataset_list')
async def get_system_ragflow_list(
request: Request,
ragflow_list_query: Any, # 使用Any避免导入具体模型类
):
"""获取数据集列表"""
result = RAGFlowService.get_ragflow_dataset_list_services(None, ragflow_list_query)
return parse_result(result)
@ragflowController.post('/create_dataset')
async def create_dataset(
create_dataset_params: Any, # 使用Any避免导入具体模型类
):
"""创建数据集"""
result = RAGFlowService.create_dataset_services(create_dataset_params)
return parse_result(result)
@ragflowController.post('/delete_datasets')
async def delete_datasets(
delete_params: Any, # 使用Any避免导入具体模型类
):
"""删除数据集"""
result = RAGFlowService.delete_datasets_services(delete_params)
return parse_result(result)
def stream_cached_response(cached_answer: str, chat_id: str, start_time: float, cache_source: str = 'cache') -> Generator[str, None, None]:
"""
流式返回缓存的答案
Args:
cached_answer: 缓存的答案文本
chat_id: 会话ID
start_time: 请求开始时间
cache_source: 缓存来源 ('static_qa' 'rag_history')
"""
import time
server_stream_start = time.time()
logger.info(f"[CACHE_STREAM {server_stream_start:.3f}] 🚀 开始流式返回缓存答案chat_id: {chat_id}")
# 立即发送连接建立消息
connection_time = time.time()
ping_message = "event: ping\ndata: {\"status\": \"connected\"}\n\n"
yield ping_message
logger.info(f"[CACHE_STREAM {connection_time:.3f}] 📡 连接建立ping发送耗时: {connection_time - server_stream_start:.3f}s")
# 模拟流式输出效果(可选:如果是完整答案,可以选择立即返回或模拟流式)
# 这里我们选择模拟流式输出,每次发送一小部分,模拟打字效果
if cached_answer:
# 将答案分块发送,模拟打字效果
chunk_size = 10 # 每个块10个字符
answer_chunks = [cached_answer[i:i+chunk_size] for i in range(0, len(cached_answer), chunk_size)]
for i, chunk in enumerate(answer_chunks):
chunk_time = time.time()
# 首token延迟
if i == 0:
latency = time.perf_counter() - start_time
logger.info(f"[CACHE_STREAM {chunk_time:.3f}] 🎯 首token到达缓存耗时: {latency:.3f}s")
body = {'answer': chunk, 'chunk_index': i, 'total_chunks': len(answer_chunks)}
yield format_sse(body)
# 小延迟模拟打字效果(可调整或移除)
# time.sleep(0.01)
logger.info(f"[CACHE_STREAM {chunk_time:.3f}] 📝 缓存答案流式发送完成,共 {len(answer_chunks)} 个chunk")
# 流结束
stream_end_time = time.time()
end_message = format_sse({
'status': 'completed',
'from_cache': True,
'source': cache_source,
'total_time': stream_end_time - server_stream_start
}, event='end')
yield end_message
logger.info(f"[CACHE_STREAM {stream_end_time:.3f}] 🏁 缓存流式响应完成")
if cached_answer:
logger.info(f"[CACHE_STREAM {stream_end_time:.3f}] 📊 缓存答案长度: {len(cached_answer)} 字符")
total_time = time.perf_counter() - start_time
logger.info(f'[CACHE_STREAM {time.time():.3f}] ⏱️ Total Cache Stream Duration ({chat_id}): {total_time:.3f}s')
async def stream_kb_es_response(
*,
question: str,
chunks: list[dict],
chat_id: str,
start_time: float,
cache_store_func=None,
retrieve_ms: float | None = None,
) -> AsyncGenerator[str, None]:
import time
server_stream_start = time.time()
logger.info(f"[KB_ES_STREAM {server_stream_start:.3f}] 开始流式响应处理chat_id: {chat_id}")
ping_message = 'event: ping\ndata: {"status": "connected"}\n\n'
yield ping_message
# 结构化Q&A命中时直接返回 answer最快不走 LLM
if chunks:
top = chunks[0]
top_answer = (top.get('answer') or '').strip()
if top_answer:
chunk_size = 12
for i in range(0, len(top_answer), chunk_size):
if i == 0:
latency = time.perf_counter() - start_time
logger.info(
f"[KB_ES_STREAM {time.time():.3f}] 首token到达(抽取式)ttft={latency:.3f}s | retrieve_ms={retrieve_ms} | chat_id={chat_id}"
)
yield format_sse({'answer': top_answer[i : i + chunk_size], 'source': 'kb_es'})
yield format_sse({'status': 'completed', 'source': 'kb_es'}, event='end')
if cache_store_func and len(top_answer.strip()) >= 10:
try:
await cache_store_func(top_answer)
except Exception as e:
logger.warning(f"[KB_ES_STREAM] 缓存存储失败: {e}")
return
context_parts = []
for i, c in enumerate(chunks[: KBConfig.KB_TOP_K], 1):
title = (c.get('title') or '').strip()
source = (c.get('source') or '').strip()
content = (c.get('content') or '').strip()
header = f"[{i}]"
if title:
header += f" {title}"
if source:
header += f" ({source})"
context_parts.append(f"{header}\n{content}")
context = "\n\n".join(context_parts)
system_prompt = (
"你是公司内部知识库助手。请严格基于【已知资料】回答;如果资料不足以回答,直接说明不知道并提示用户补充关键词。"
"回答要简洁。"
)
messages = [
{"role": "system", "content": f"{system_prompt}\n\n【已知资料】\n{context}"},
{"role": "user", "content": question},
]
full_answer = ''
first_token_sent = False
try:
client = DeepSeekAPIClient()
stream = await client.chat_completion(
messages=messages,
temperature=0.2,
max_tokens=512,
stream=True,
)
async for chunk in stream:
await asyncio.sleep(0)
try:
delta = chunk.choices[0].delta.content or ''
except Exception:
delta = ''
if not delta:
continue
if not first_token_sent:
first_token_sent = True
latency = time.perf_counter() - start_time
logger.info(
f"[KB_ES_STREAM {time.time():.3f}] 首token到达ttft={latency:.3f}s | retrieve_ms={retrieve_ms} | chat_id={chat_id}"
)
full_answer += delta
yield format_sse({'answer': delta, 'source': 'kb_es'})
yield format_sse({'status': 'completed', 'source': 'kb_es'}, event='end')
except Exception as exc:
logger.exception(f"[KB_ES_STREAM] 流式对话异常: {exc}")
yield format_sse({'message': str(exc)}, event='error')
finally:
total_time = time.perf_counter() - start_time
logger.info(f"[KB_ES_STREAM {time.time():.3f}] Total Stream Duration ({chat_id}): {total_time:.3f}s")
if cache_store_func and full_answer and len(full_answer.strip()) >= 10:
try:
await cache_store_func(full_answer)
except Exception as e:
logger.warning(f"[KB_ES_STREAM] 缓存存储失败: {e}")

View File

@ -1,376 +0,0 @@
# from datetime import datetime
import hashlib
import json
import time
from typing import List
from fastapi import APIRouter, Depends, Request, UploadFile, File
from fastapi.responses import StreamingResponse
# from pydantic_validation_decorator import ValidateFields
# from sqlalchemy.ext.asyncio import AsyncSession
# from config.enums import BusinessType
# from config.get_db import get_db
from module_admin.aspect.interface_auth import CheckRoleInterfaceAuth
# from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel
# from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.ragflow_service import RAGFlowService
from module_admin.service.search_service import SearchService, SearchServiceError
from utils.log_util import logger
# from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
from module_admin.entity.vo.ragflow_vo import RagflowListQueryModel, ListDocumentsQueryModel, UpdateFileModel, DeleteFileModel, CreateDatasetModel, DocumentIdsModel, UpdateChatAssistantModel,\
CreateSessionWithChatModel, ConverseWithChatAssistantModel
# from config.env import RAGFlowConfig
import asyncio
ragflowController = APIRouter(prefix="/system/ragflow", dependencies=[Depends(LoginService.get_current_user)])
# 查看数据集列表
@ragflowController.post("/dataset_list"
# , response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth("system:ragflow:list"))]"
)
async def get_system_ragflow_list(
request: Request,
rage_flow_dastset_query: RagflowListQueryModel ,
# query_db: AsyncSession = Depends(get_db),
):
result = await RAGFlowService.get_ragflow_dataset_list_services(None, rage_flow_dastset_query)
return parse_result(result)
# 创建数据集
@ragflowController.post('/create_dataset')
async def create_dataset(
request: Request,
create_dataset_params: CreateDatasetModel,
):
result = await RAGFlowService.create_dataset_services(create_dataset_params)
return parse_result(result)
# 更新数据集
@ragflowController.post('/update_dataset/{dataset_id}')
async def update_dataset(
request: Request,
dataset_id: str,
update_dataset_params: CreateDatasetModel,
):
result = await RAGFlowService.update_dataset_services(dataset_id, update_dataset_params)
return parse_result(result)
# 列出数据集中文档列表
@ragflowController.get("/list_documents/{dataset_id}")
async def list_documents_by_dataset_id(
request: Request,
dataset_id: str,
list_documents_query: ListDocumentsQueryModel = Depends(ListDocumentsQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
):
"""
列出数据集中文档列表
"""
print(list_documents_query)
result = await RAGFlowService.list_documents_services(None, dataset_id, list_documents_query)
return parse_result(result)
# 上传文件到数据集
@ragflowController.post("/upload_file/{dataset_id}")
async def upload_file_dataset(
dataset_id: str,
files: List[UploadFile] = File(...),
# query_db: AsyncSession = Depends(get_db),
):
"""
上传文件到数据集
"""
# print(file)
result = await RAGFlowService.upload_file_dataset_services(None, dataset_id ,files)
return parse_result(result)
# 更新文档
@ragflowController.post("/update_file/{dataset_id}/{document_id}")
async def update_file_dataset(
dataset_id: str,
document_id: str,
update_params: UpdateFileModel,
# query_db: AsyncSession = Depends(get_db),
):
"""
更新文件到数据集
"""
# print(file)
result = await RAGFlowService.update_file_dataset_services(dataset_id ,document_id, update_params)
return parse_result(result)
# 开始解析文档
@ragflowController.post('/parse_documents/{dataset_id}')
async def parse_documents(
dataset_id: str,
parse_params: DocumentIdsModel,
# query_db: AsyncSession = Depends(get_db),
):
result = await RAGFlowService.parse_documents_services(dataset_id, parse_params)
return parse_result(result)
# 停止解析文档
@ragflowController.post('/stop_parse_documents/{dataset_id}')
async def stop_parse_documents(
dataset_id: str,
parse_params: DocumentIdsModel,
# query_db: AsyncSession = Depends(get_db),
):
result = await RAGFlowService.stop_parse_documents_services(dataset_id, parse_params)
return parse_result(result)
# 删除文档
@ragflowController.post('/delete_file/{dataset_id}')
async def delete_file(
dataset_id: str,
delete_params: DeleteFileModel,
# query_db: AsyncSession = Depends(get_db),
):
"""
删除文件
"""
result = await RAGFlowService.delete_file_services(dataset_id, delete_params)
return parse_result(result)
# 删除数据集
@ragflowController.post('/delete_datasets')
async def delete_datasets(
delete_params: DeleteFileModel,
# query_db: AsyncSession = Depends(get_db),
):
"""
删除数据集
"""
result = await RAGFlowService.delete_datasets_services(delete_params)
return parse_result(result)
# 查看聊天助手列表
@ragflowController.post('/get_chat_assistant_list')
async def get_chat_assistant_list(
query_params: RagflowListQueryModel,
):
"""
查看聊天助手列表
"""
result = await RAGFlowService.get_chat_assistant_list_services(query_params)
return parse_result(result)
# pass
# 更新聊天助手
@ragflowController.post('/update_chat_assistant')
async def update_chat_assistant(
update_params: UpdateChatAssistantModel,
):
"""
更新聊天助手
"""
result = await RAGFlowService.update_chat_assistant_services(update_params)
return parse_result(result)
# 创建属于聊天助手的会话
@ragflowController.post('/create_session_with_chat')
async def create_session_with_chat(
create_params: CreateSessionWithChatModel,
):
"""
创建属于聊天助手的会话
"""
result = await RAGFlowService.create_session_with_chat_services(create_params)
return parse_result(result)
# 与聊天助手进行对话
@ragflowController.post('/converse_with_chat_assistant')
async def converse_with_chat_assistant(
request: Request,
converse_params: ConverseWithChatAssistantModel,
):
"""
与聊天助手进行对话
"""
start_time = time.perf_counter()
redis = getattr(request.app.state, 'redis', None)
cache_key = None
# 检查是否应该使用搜索服务 (Router Strategy)
# Using 'glm-4-flash' to classify intent: SEARCH vs RAG
t0 = time.perf_counter()
intent = await SearchService.classify_intent(converse_params.question)
logger.info(f"[RAG_PROFILE] Intent Router ({converse_params.chat_id}): {intent} | Time: {time.perf_counter() - t0:.3f}s | Query: {converse_params.question}")
if intent == 'SEARCH':
return await SearchService.handle_search_chat(converse_params, redis)
if not converse_params.stream and redis:
cache_key = build_chat_cache_key(converse_params.chat_id, converse_params.question)
cached = await redis.get(cache_key)
if cached:
logger.info('ragflow对话命中缓存: chat=%s', converse_params.chat_id)
return ResponseUtil.success(json.loads(cached))
# Revert to Native RAGFlow Service (OpenAI endpoint failed with Auth error)
t1 = time.perf_counter()
# 使用同步Generator更简单
result = RAGFlowService.converse_with_chat_assistant_services(converse_params)
logger.info(f"[RAG_PROFILE] RAG Init/Connect ({converse_params.chat_id}): {time.perf_counter() - t1:.3f}s")
if converse_params.stream:
async def stream_response():
last_answer = ""
first_token_received = False
start_stream_time = time.perf_counter()
try:
# 将同步Generator转换为异步迭代
loop = asyncio.get_event_loop()
for chunk in result:
# 在事件循环中运行CPU密集型操作
await asyncio.sleep(0) # 让出控制权,允许其他协程运行
if not first_token_received:
first_token_received = True
latency = time.perf_counter() - start_stream_time
logger.info(f"[RAG_PROFILE] Time to First Token ({converse_params.chat_id}): {latency:.3f}s")
# Native RAGFlow returns cumulative text in 'answer' field
# Chunk structure: {'data': {'answer': 'Cumulative Text...'}}
payload = chunk.get('data') if isinstance(chunk, dict) else chunk
if not payload:
continue
body = payload if isinstance(payload, dict) else {'data': payload}
if isinstance(body, dict) and 'answer' in body:
# Inspect for errors even in stream
if isinstance(chunk, dict) and chunk.get('code') and chunk.get('code') != 0:
logger.error(f"RAGFlow Stream Error: {chunk}")
current_answer = body['answer']
# Calculate Delta
if current_answer.startswith(last_answer):
delta = current_answer[len(last_answer):]
if delta:
body['answer'] = delta # Send only the new part
last_answer = current_answer
yield format_sse(body)
else:
# Context reset (unlikely but safe fallback)
last_answer = current_answer
yield format_sse(body)
else:
yield format_sse(body)
yield format_sse({'status': 'completed'}, event='end')
except Exception as exc:
logger.exception('[RAG_PROFILE] ragflow流式对话异常: %s', exc)
yield format_sse({'message': str(exc)}, event='error')
finally:
total_time = time.perf_counter() - start_time
logger.info(f'[RAG_PROFILE] Total Stream Duration ({converse_params.chat_id}): {total_time:.3f}s')
return StreamingResponse(stream_response(), media_type='text/event-stream')
response = parse_result(result)
if redis and cache_key and isinstance(result, dict) and result.get('code') == 0:
await redis.set(cache_key, json.dumps(result.get('data'), ensure_ascii=False), ex=60)
logger.info(f'[RAG_PROFILE] Total Sync Duration ({converse_params.chat_id}): {time.perf_counter() - start_time:.3f}s')
return response
# return parse_result(result)
# 获取用户权限
@ragflowController.get('/get_user_permission', dependencies=[Depends(CheckRoleInterfaceAuth('pad'))])
async def get_user_permission(current_user = Depends(LoginService.get_current_user)):
"""
获取用户权限
"""
user_auth_list = current_user.permissions
print(user_auth_list)
return ResponseUtil.success(data=user_auth_list)
def parse_result(result):
code = result.get('code', 0)
if code != 0:
msg = result.get('message') or result.get('msg') or '接口异常'
return ResponseUtil.error(msg=msg, data=result.get('data', None))
return ResponseUtil.success(data=result.get('data', None))
def build_chat_cache_key(chat_id: str, question: str) -> str:
digest = hashlib.sha256(question.encode('utf-8')).hexdigest()
return f'ragflow:chat:{chat_id}:{digest}'
def format_sse(data: dict, event: str | None = None) -> str:
payload = json.dumps(data, ensure_ascii=False)
prefix = f'event: {event}\n' if event else ''
return f'{prefix}data: {payload}\n\n'
async def aiter_sync_generator(sync_gen):
"""将同步 Generator 转换为异步迭代器"""
loop = asyncio.get_event_loop()
try:
while True:
# 在线程池中获取下一个值
value = await loop.run_in_executor(None, next, sync_gen, None)
if value is None:
break
yield value
except StopIteration:
pass
import asyncio
import hashlib
import json
import time
from typing import AsyncIterator, Union
import aiofiles
import redis
from fastapi import Depends, Request, Response
from fastapi.responses import StreamingResponse
from fastapi_controller.decorators import Controller
from fastapi_controller.dependencies import LoginService
from fastapi_controller.response import ResponseUtil
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.service.ragflow_service import RAGFlowService
from module_admin.service.search_service import SearchService
from module_admin.service.login_service import CheckRoleInterfaceAuth
from module_admin.model.ragflow_models import (
ConverseWithChatAssistantModel,
CreateSessionWithChatModel,
DeleteFileModel,
DocumentIdsModel,
RagflowListQueryModel,
UpdateChatAssistantModel,
)
import logger as logger_module

View File

@ -1,106 +0,0 @@
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth, CheckRoleInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.robot_action_service import Robot_actionService
from module_admin.entity.vo.robot_action_vo import DeleteRobot_actionModel, Robot_actionModel, Robot_actionPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
from datetime import datetime
robot_actionController = APIRouter(prefix='/system/robot_action', dependencies=[Depends(LoginService.get_current_user)])
@robot_actionController.get(
'/list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:list'))]
)
async def get_system_robot_action_list(
request: Request,
robot_action_page_query: Robot_actionPageQueryModel = Depends(Robot_actionPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
robot_action_page_query_result = await Robot_actionService.get_robot_action_list_services(query_db, robot_action_page_query, is_page=False)
logger.info('获取成功')
return ResponseUtil.success(data=robot_action_page_query_result)
# @robot_actionController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:add'))])
# @ValidateFields(validate_model='add_robot_action')
# @Log(title='机器人动作', business_type=BusinessType.INSERT)
# async def add_system_robot_action(
# request: Request,
# add_robot_action: Robot_actionModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_robot_action.update_time = datetime.now()
# add_robot_action_result = await Robot_actionService.add_robot_action_services(query_db, add_robot_action)
# logger.info(add_robot_action_result.message)
# return ResponseUtil.success(msg=add_robot_action_result.message)
@robot_actionController.put(''
# , dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:edit'))]
)
@ValidateFields(validate_model='edit_robot_action')
@Log(title='机器人动作', business_type=BusinessType.UPDATE)
async def edit_system_robot_action(
request: Request,
edit_robot_action: Robot_actionModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_robot_action.update_by = current_user.user.user_name
edit_robot_action.update_time = datetime.now()
edit_robot_action_result = await Robot_actionService.edit_robot_action_services(query_db, edit_robot_action)
logger.info(edit_robot_action_result.message)
return ResponseUtil.success(msg=edit_robot_action_result.message)
# @robot_actionController.delete('/{ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:remove'))])
# @Log(title='机器人动作', business_type=BusinessType.DELETE)
# async def delete_system_robot_action(request: Request, ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_robot_action = DeleteRobot_actionModel(ids=ids)
# delete_robot_action_result = await Robot_actionService.delete_robot_action_services(query_db, delete_robot_action)
# logger.info(delete_robot_action_result.message)
# return ResponseUtil.success(msg=delete_robot_action_result.message)
# @robot_actionController.get(
# '/{id}', response_model=Robot_actionModel, dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:query'))]
# )
# async def query_detail_system_robot_action(request: Request, id: int, query_db: AsyncSession = Depends(get_db)):
# robot_action_detail_result = await Robot_actionService.robot_action_detail_services(query_db, id)
# logger.info(f'获取id为{id}的信息成功')
# return ResponseUtil.success(data=robot_action_detail_result)
# @robot_actionController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:robot_action:export'))])
# @Log(title='机器人动作', business_type=BusinessType.EXPORT)
# async def export_system_robot_action_list(
# request: Request,
# robot_action_page_query: Robot_actionPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# robot_action_query_result = await Robot_actionService.get_robot_action_list_services(query_db, robot_action_page_query, is_page=False)
# robot_action_export_result = await Robot_actionService.export_robot_action_list_services(robot_action_query_result)
# logger.info('导出成功')
# return ResponseUtil.streaming(data=bytes2file_response(robot_action_export_result))

View File

@ -1,110 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.role_service import RoleService
from module_admin.entity.vo.role_vo import DeleteRoleModel, RoleModel, RolePageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
"""
当前用不到这个接口
"""
# roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)])
#
#
# @roleController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]
# )
# async def get_system_role_list(
# request: Request,
# role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# role_page_query_result = await RoleService.get_role_list_services(query_db, role_page_query, is_page=True)
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=role_page_query_result)
# @roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))])
# @ValidateFields(validate_model='add_role')
# @Log(title='系统角色', business_type=BusinessType.INSERT)
# async def add_system_role(
# request: Request,
# add_role: RoleModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_role.create_time = datetime.now()
# add_role.create_by = current_user.user.user_name
# add_role.update_time = datetime.now()
# add_role.update_by = current_user.user.user_name
# add_role_result = await RoleService.add_role_services(query_db, add_role)
# logger.info(add_role_result.message)
#
# return ResponseUtil.success(msg=add_role_result.message)
# @roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
# @ValidateFields(validate_model='edit_role')
# @Log(title='系统角色', business_type=BusinessType.UPDATE)
# async def edit_system_role(
# request: Request,
# edit_role: RoleModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_role.update_by = current_user.user.user_name
# edit_role.update_time = datetime.now()
# edit_role_result = await RoleService.edit_role_services(query_db, edit_role)
# logger.info(edit_role_result.message)
#
# return ResponseUtil.success(msg=edit_role_result.message)
# @roleController.delete('/{robot_role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))])
# @Log(title='系统角色', business_type=BusinessType.DELETE)
# async def delete_system_role(request: Request, robot_role_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_role = DeleteRoleModel(robotRoleIds=robot_role_ids)
# delete_role_result = await RoleService.delete_role_services(query_db, delete_role)
# logger.info(delete_role_result.message)
#
# return ResponseUtil.success(msg=delete_role_result.message)
# @roleController.get(
# '/{robot_role_id}', response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]
# )
# async def query_detail_system_role(request: Request, robot_role_id: int, query_db: AsyncSession = Depends(get_db)):
# role_detail_result = await RoleService.role_detail_services(query_db, robot_role_id)
# logger.info(f'获取robot_role_id为{robot_role_id}的信息成功')
#
# return ResponseUtil.success(data=role_detail_result)
# @roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))])
# @Log(title='系统角色', business_type=BusinessType.EXPORT)
# async def export_system_role_list(
# request: Request,
# role_page_query: RolePageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# role_query_result = await RoleService.get_role_list_services(query_db, role_page_query, is_page=False)
# role_export_result = await RoleService.export_role_list_services(role_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(role_export_result))

View File

@ -1,155 +0,0 @@
from fastapi import APIRouter, Depends, Form, Request, Response
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.dao.robot_role_pairing_dao import PairingDao
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.robot_role_pairing_service import PairingService
from module_admin.entity.vo.robot_role_pairing_vo import DeletePairingModel, PairingModel, PairingPageQueryModel, \
ChangeRobotRoleModel
from utils.common_util import bytes2file_response, export_list2excel
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
from datetime import datetime
pairingController = APIRouter(prefix='/system/robot_role'
# , dependencies=[Depends(LoginService.get_current_user)]
)
# 获取机器人角色
@pairingController.get(
'/{robot_id}',
)
async def get_system_role_pairing_list(
request: Request,
robot_id: int,
query_db: AsyncSession = Depends(get_db),
):
# 获取分页数据
pairing_list, style = await PairingService.get_role_pairing_list_services(query_db, robot_id)
return ResponseUtil.success(data={"role": pairing_list, "style":style})
# 获取机器人角色新版
@pairingController.get(
'/v1/{robot_id}',
)
async def get_system_role_pairing_list_v1(
request: Request,
robot_id: int,
query_db: AsyncSession = Depends(get_db),
):
pairing_list, style = await PairingService.get_role_pairing_list_services_v1(query_db, robot_id)
return ResponseUtil.success(data={"role": pairing_list, "style":style})
@pairingController.post(
'/change',
)
async def change_robot_role(
request: Request,
change_pairing: ChangeRobotRoleModel,
query_db: AsyncSession = Depends(get_db),
):
await PairingService.change_robot_role_services(query_db,change_pairing)
return ResponseUtil.success()
# @pairingController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:list'))]
# )
# async def get_system_pairing_list(
# request: Request,
# pairing_page_query: PairingPageQueryModel = Depends(PairingPageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# pairing_page_query_result = await PairingService.get_pairing_list_services(query_db, pairing_page_query, is_page=True)
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=pairing_page_query_result)
#
#
# @pairingController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:add'))])
# @ValidateFields(validate_model='add_pairing')
# @Log(title='角色-机器人-映射', business_type=BusinessType.INSERT)
# async def add_system_pairing(
# request: Request,
# add_pairing: PairingModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_pairing.update_time = datetime.now()
# add_pairing.update_by = current_user.user.user_name
# add_pairing_result = await PairingService.add_pairing_services(query_db, add_pairing)
# logger.info(add_pairing_result.message)
#
# return ResponseUtil.success(msg=add_pairing_result.message)
#
#
# @pairingController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:edit'))])
# @ValidateFields(validate_model='edit_pairing')
# @Log(title='角色-机器人-映射', business_type=BusinessType.UPDATE)
# async def edit_system_pairing(
# request: Request,
# edit_pairing: PairingModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_pairing.update_by = current_user.user.user_name
# edit_pairing.update_time = datetime.now()
# edit_pairing_result = await PairingService.edit_pairing_services(query_db, edit_pairing)
# logger.info(edit_pairing_result.message)
#
# return ResponseUtil.success(msg=edit_pairing_result.message)
#
#
# @pairingController.delete('/{pairing_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:remove'))])
# @Log(title='角色-机器人-映射', business_type=BusinessType.DELETE)
# async def delete_system_pairing(request: Request, pairing_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_pairing = DeletePairingModel(pairingIds=pairing_ids)
# delete_pairing_result = await PairingService.delete_pairing_services(query_db, delete_pairing)
# logger.info(delete_pairing_result.message)
#
# return ResponseUtil.success(msg=delete_pairing_result.message)
#
#
# @pairingController.get(
# '/{pairing_id}', response_model=PairingModel, dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:query'))]
# )
# async def query_detail_system_pairing(request: Request, pairing_id: int, query_db: AsyncSession = Depends(get_db)):
# pairing_detail_result = await PairingService.pairing_detail_services(query_db, pairing_id)
# logger.info(f'获取pairing_id为{pairing_id}的信息成功')
#
# return ResponseUtil.success(data=pairing_detail_result)
#
#
# @pairingController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:pairing:export'))])
# @Log(title='角色-机器人-映射', business_type=BusinessType.EXPORT)
# async def export_system_pairing_list(
# request: Request,
# pairing_page_query: PairingPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# pairing_query_result = await PairingService.get_pairing_list_services(query_db, pairing_page_query, is_page=False)
# pairing_export_result = await PairingService.export_pairing_list_services(pairing_query_result)
# logger.info('导出成功')
# # return Response(
# # content=pairing_export_result,
# # media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
# # headers={
# # "Content-Disposition": "attachment; filename=export.xlsx"
# # }
# # )
# return ResponseUtil.streaming(data=bytes2file_response(pairing_export_result))

View File

@ -1,283 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.data_scope import GetDataScope
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.dept_vo import DeptModel
from module_admin.entity.vo.role_vo import AddRoleModel, DeleteRoleModel, RoleModel, RolePageQueryModel
from module_admin.entity.vo.user_vo import CrudUserRoleModel, CurrentUserModel, UserRolePageQueryModel
from module_admin.service.dept_service import DeptService
from module_admin.service.login_service import LoginService
from module_admin.service.role_service import RoleService
from module_admin.service.user_service import UserService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
roleController = APIRouter(prefix='/system/role', dependencies=[Depends(LoginService.get_current_user)])
@roleController.get('/deptTree/{role_id}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))])
async def get_system_role_dept_tree(
request: Request,
role_id: int,
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql)
role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id)
role_dept_query_result.depts = dept_query_result
logger.info('获取成功')
return ResponseUtil.success(model_content=role_dept_query_result)
@roleController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))]
)
async def get_system_role_list(
request: Request,
role_page_query: RolePageQueryModel = Depends(RolePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
role_page_query_result = await RoleService.get_role_list_services(
query_db, role_page_query, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_page_query_result)
@roleController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:add'))])
@ValidateFields(validate_model='add_role')
@Log(title='角色管理', business_type=BusinessType.INSERT)
async def add_system_role(
request: Request,
add_role: AddRoleModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_role.create_by = current_user.user.user_name
add_role.create_time = datetime.now()
add_role.update_by = current_user.user.user_name
add_role.update_time = datetime.now()
add_role_result = await RoleService.add_role_services(query_db, add_role)
logger.info(add_role_result.message)
return ResponseUtil.success(msg=add_role_result.message)
@roleController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@ValidateFields(validate_model='edit_role')
@Log(title='角色管理', business_type=BusinessType.UPDATE)
async def edit_system_role(
request: Request,
edit_role: AddRoleModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
await RoleService.check_role_allowed_services(edit_role)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql)
edit_role.update_by = current_user.user.user_name
edit_role.update_time = datetime.now()
edit_role_result = await RoleService.edit_role_services(query_db, edit_role)
logger.info(edit_role_result.message)
return ResponseUtil.success(msg=edit_role_result.message)
@roleController.put('/dataScope', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def edit_system_role_datascope(
request: Request,
role_data_scope: AddRoleModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
await RoleService.check_role_allowed_services(role_data_scope)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql)
edit_role = AddRoleModel(
roleId=role_data_scope.role_id,
dataScope=role_data_scope.data_scope,
deptIds=role_data_scope.dept_ids,
deptCheckStrictly=role_data_scope.dept_check_strictly,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
)
role_data_scope_result = await RoleService.role_datascope_services(query_db, edit_role)
logger.info(role_data_scope_result.message)
return ResponseUtil.success(msg=role_data_scope_result.message)
@roleController.delete('/{role_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:role:remove'))])
@Log(title='角色管理', business_type=BusinessType.DELETE)
async def delete_system_role(
request: Request,
role_ids: str,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
role_id_list = role_ids.split(',') if role_ids else []
if role_id_list:
for role_id in role_id_list:
await RoleService.check_role_allowed_services(RoleModel(roleId=int(role_id)))
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql)
delete_role = DeleteRoleModel(roleIds=role_ids, updateBy=current_user.user.user_name, updateTime=datetime.now())
delete_role_result = await RoleService.delete_role_services(query_db, delete_role)
logger.info(delete_role_result.message)
return ResponseUtil.success(msg=delete_role_result.message)
@roleController.get(
'/{role_id}', response_model=RoleModel, dependencies=[Depends(CheckUserInterfaceAuth('system:role:query'))]
)
async def query_detail_system_role(
request: Request,
role_id: int,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql)
role_detail_result = await RoleService.role_detail_services(query_db, role_id)
logger.info(f'获取role_id为{role_id}的信息成功')
return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True))
@roleController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:role:export'))])
@Log(title='角色管理', business_type=BusinessType.EXPORT)
async def export_system_role_list(
request: Request,
role_page_query: RolePageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
# 获取全量数据
role_query_result = await RoleService.get_role_list_services(
query_db, role_page_query, data_scope_sql, is_page=False
)
role_export_result = await RoleService.export_role_list_services(role_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(role_export_result))
@roleController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@Log(title='角色管理', business_type=BusinessType.UPDATE)
async def reset_system_role_status(
request: Request,
change_role: AddRoleModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
await RoleService.check_role_allowed_services(change_role)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql)
edit_role = AddRoleModel(
roleId=change_role.role_id,
status=change_role.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_role_result = await RoleService.edit_role_services(query_db, edit_role)
logger.info(edit_role_result.message)
return ResponseUtil.success(msg=edit_role_result.message)
@roleController.get(
'/authUser/allocatedList',
response_model=PageResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))],
)
async def get_system_allocated_user_list(
request: Request,
user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(
query_db, user_role, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_user_allocated_page_query_result)
@roleController.get(
'/authUser/unallocatedList',
response_model=PageResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('system:role:list'))],
)
async def get_system_unallocated_user_list(
request: Request,
user_role: UserRolePageQueryModel = Depends(UserRolePageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(
query_db, user_role, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_user_unallocated_page_query_result)
@roleController.put('/authUser/selectAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def add_system_role_user(
request: Request,
add_role_user: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query),
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql)
add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user)
logger.info(add_role_user_result.message)
return ResponseUtil.success(msg=add_role_user_result.message)
@roleController.put('/authUser/cancel', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def cancel_system_role_user(
request: Request, cancel_user_role: CrudUserRoleModel, query_db: AsyncSession = Depends(get_db)
):
cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role)
logger.info(cancel_user_role_result.message)
return ResponseUtil.success(msg=cancel_user_role_result.message)
@roleController.put('/authUser/cancelAll', dependencies=[Depends(CheckUserInterfaceAuth('system:role:edit'))])
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def batch_cancel_system_role_user(
request: Request,
batch_cancel_user_role: CrudUserRoleModel = Depends(CrudUserRoleModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role)
logger.info(batch_cancel_user_role_result.message)
return ResponseUtil.success(msg=batch_cancel_user_role_result.message)

View File

@ -1,79 +0,0 @@
"""
系统定时任务
"""
from config.get_scheduler import scheduler
from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.interval import IntervalTrigger
from module_admin.service.haikang_service import HaiKangService
from module_admin.service.compreface_service import ComprefaceService
from utils.log_util import logger
# 定时获取访客图片并上传compreface
async def download_visitor_image_and_upload_compreface():
"""
定时任务获取海康访客图片并上传到compreface进行人脸识别
同时删除已过期的访客人脸数据
执行频率每2分钟一次
"""
try:
logger.info('开始执行定时任务获取访客图片并上传compreface')
# 获取所有有效状态的访客图片visitorStatus=1表示正常状态
visitor_name_list = await HaiKangService.get_all_visitor_pictures(visitorStatus=1)
logger.info(f'获取到 {len(visitor_name_list)} 张有效访客图片')
# 如果有新的访客图片将访客图片上传到compreface
if visitor_name_list:
result = await ComprefaceService.face_addition_batch_service(visitor_name_list)
logger.info(f'访客图片上传compreface结果: {result}')
else:
logger.info('没有新的访客图片需要处理')
# 删除过期的访客人脸数据
# 从visitor_name_list中提取所有访客的名字
active_visitor_names = [name for _, name in visitor_name_list] if visitor_name_list else []
logger.info(f'开始删除过期访客人脸,当前有效访客数量: {len(active_visitor_names)}')
delete_result = await ComprefaceService.delete_expired_visitor_faces_service(active_visitor_names)
if delete_result.get('error'):
logger.error(f'删除过期访客失败: {delete_result.get("error")}')
else:
logger.info(
f'删除过期访客完成 - 成功删除: {delete_result.get("deleted_count")} 个, '
f'失败: {delete_result.get("failed_count")}'
)
if delete_result.get('deleted_subjects'):
logger.info(f'已删除的访客: {", ".join(delete_result.get("deleted_subjects"))}')
if delete_result.get('failed_subjects'):
logger.warning(f'删除失败的访客: {delete_result.get("failed_subjects")}')
logger.info('定时任务执行完成获取访客图片并上传compreface')
except Exception as e:
logger.error(f'定时任务执行失败获取访客图片并上传compreface - {str(e)}', exc_info=True)
# 初始化定时任务
def init_scheduled_tasks():
"""
初始化所有定时任务
在应用启动时调用此方法
"""
# 添加访客图片上传任务每2分钟执行一次
scheduler.add_job(
func=download_visitor_image_and_upload_compreface,
trigger=IntervalTrigger(minutes=2),
id='download_visitor_image_task',
name='定时获取访客图片并上传compreface',
replace_existing=True,
max_instances=1, # 同一时间只允许一个实例运行
)
logger.info('定时任务已添加download_visitor_image_and_upload_compreface (每2分钟执行一次)')

View File

@ -1,21 +0,0 @@
from fastapi import APIRouter, Depends, Request
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.server_vo import ServerMonitorModel
from module_admin.service.login_service import LoginService
from module_admin.service.server_service import ServerService
from utils.response_util import ResponseUtil
from utils.log_util import logger
serverController = APIRouter(prefix='/monitor/server', dependencies=[Depends(LoginService.get_current_user)])
@serverController.get(
'', response_model=ServerMonitorModel, dependencies=[Depends(CheckUserInterfaceAuth('monitor:server:list'))]
)
async def get_monitor_server_info(request: Request):
# 获取全量数据
server_info_query_result = await ServerService.get_server_monitor_info()
logger.info('获取成功')
return ResponseUtil.success(data=server_info_query_result)

View File

@ -1,106 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.sys_alert_service import Sys_alertService
from module_admin.entity.vo.sys_alert_vo import DeleteSys_alertModel, Sys_alertModel, Sys_alertPageQueryModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
sys_alertController = APIRouter(prefix='/system/sys_alert', dependencies=[Depends(LoginService.get_current_user)])
# @sys_alertController.get(
# '/list', response_model=PageResponseModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:list'))]
# )
# async def get_system_sys_alert_list(
# request: Request,
# sys_alert_page_query: Sys_alertPageQueryModel = Depends(Sys_alertPageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# sys_alert_page_query_result = await Sys_alertService.get_sys_alert_list_services(query_db, sys_alert_page_query, is_page=True)
# logger.info('获取成功')
# return ResponseUtil.success(model_content=sys_alert_page_query_result)
# @sys_alertController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:add'))])
# @ValidateFields(validate_model='add_sys_alert')
# @Log(title='系统告警', business_type=BusinessType.INSERT)
# async def add_system_sys_alert(
# request: Request,
# add_sys_alert: Sys_alertModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_sys_alert.create_time = datetime.now()
# add_sys_alert.create_by = current_user.user.user_name
# add_sys_alert.update_time = datetime.now()
# add_sys_alert.update_by = current_user.user.user_name
# add_sys_alert_result = await Sys_alertService.add_sys_alert_services(query_db, add_sys_alert)
# logger.info(add_sys_alert_result.message)
# return ResponseUtil.success(msg=add_sys_alert_result.message)
# @sys_alertController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:edit'))])
# @ValidateFields(validate_model='edit_sys_alert')
# @Log(title='系统告警', business_type=BusinessType.UPDATE)
# async def edit_system_sys_alert(
# request: Request,
# edit_sys_alert: Sys_alertModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_sys_alert.update_by = current_user.user.user_name
# edit_sys_alert.update_time = datetime.now()
# edit_sys_alert_result = await Sys_alertService.edit_sys_alert_services(query_db, edit_sys_alert)
# logger.info(edit_sys_alert_result.message)
# return ResponseUtil.success(msg=edit_sys_alert_result.message)
# @sys_alertController.delete('/{ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:remove'))])
# @Log(title='系统告警', business_type=BusinessType.DELETE)
# async def delete_system_sys_alert(request: Request, ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_sys_alert = DeleteSys_alertModel(ids=ids)
# delete_sys_alert_result = await Sys_alertService.delete_sys_alert_services(query_db, delete_sys_alert)
# logger.info(delete_sys_alert_result.message)
# return ResponseUtil.success(msg=delete_sys_alert_result.message)
# @sys_alertController.get(
# '/{id}', response_model=Sys_alertModel, dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:query'))]
# )
# async def query_detail_system_sys_alert(request: Request, id: int, query_db: AsyncSession = Depends(get_db)):
# sys_alert_detail_result = await Sys_alertService.sys_alert_detail_services(query_db, id)
# logger.info(f'获取id为{id}的信息成功')
# return ResponseUtil.success(data=sys_alert_detail_result)
# @sys_alertController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_alert:export'))])
# @Log(title='系统告警', business_type=BusinessType.EXPORT)
# async def export_system_sys_alert_list(
# request: Request,
# sys_alert_page_query: Sys_alertPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# sys_alert_query_result = await Sys_alertService.get_sys_alert_list_services(query_db, sys_alert_page_query, is_page=False)
# sys_alert_export_result = await Sys_alertService.export_sys_alert_list_services(sys_alert_query_result)
# logger.info('导出成功')
# return ResponseUtil.streaming(data=bytes2file_response(sys_alert_export_result))

View File

@ -1,240 +0,0 @@
from datetime import datetime, date
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.identification_record_service import Identification_recordService
from module_admin.service.sys_statistics_service import Sys_statisticsService
from module_admin.entity.vo.sys_statistics_vo import DeleteSys_statisticsModel, Sys_statisticsModel, Sys_statisticsPageQueryModel
from module_admin.entity.vo.identification_record_vo import Identification_recordModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
sys_statisticsController = APIRouter(prefix='/system/sys_statistics', dependencies=[Depends(LoginService.get_current_user)])
# 添加识别记录
@sys_statisticsController.post(
'/add_identification_record'
)
async def add_system_identification_record(
request: Request,
add_identification_record: Identification_recordModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
try:
# 设置创建时间和创建者
add_identification_record.create_time = datetime.now()
add_identification_record.create_by = current_user.user.user_name
# 调用服务层添加识别记录
result = await Identification_recordService.add_identification_record_services(query_db, add_identification_record)
if result.is_success:
logger.info(f'添加识别记录成功: {add_identification_record.person_name}')
return ResponseUtil.success(msg=result.message)
else:
logger.error(f'添加识别记录失败: {result.message}')
return ResponseUtil.error(msg=result.message)
except Exception as e:
logger.error(f'添加识别记录异常: {str(e)}')
return ResponseUtil.error(msg=f'添加识别记录失败: {str(e)}')
# 获取统计数据
@sys_statisticsController.get(
'/get_data'
)
async def get_statistics_data(
request: Request,
query_db: AsyncSession = Depends(get_db),
):
data = await Sys_statisticsService.get_statistics_data_services(query_db)
return ResponseUtil.success(data=data)
# 获取访问趋势
@sys_statisticsController.get(
'/get_visitor_count/{day}'
)
async def get_visitor_count(
request: Request,
day: int,
query_db: AsyncSession = Depends(get_db),
):
data = await Sys_statisticsService.get_visitor_count_services(query_db, day)
return ResponseUtil.success(data=data)
# 获取门禁识别成功率
@sys_statisticsController.get(
'/access_control_success_rate/{day}'
)
async def get_access_control_success_rate(
request: Request,
day: int,
query_db: AsyncSession = Depends(get_db),
):
data = await Sys_statisticsService.get_access_control_success_rate_services(query_db, day)
return ResponseUtil.success(data=data)
# 大模型调用次数加1
@sys_statisticsController.get(
'/add_model_call_count'
)
async def add_model_call_count(
request: Request,
query_db: AsyncSession = Depends(get_db),
user: CurrentUserModel = Depends(LoginService.get_current_user),
):
data = await Sys_statisticsService.add_model_call_count_services(query_db, user.user.user_name)
if data.is_success:
logger.info('大模型调用次数加1成功')
return ResponseUtil.success(msg=data.message)
else:
logger.error('大模型调用次数加1失败')
return ResponseUtil.error(msg=data.message)
# 门禁通行量次数加1
@sys_statisticsController.get(
'/add_door_pass_count'
)
async def add_door_pass_count(
request: Request,
query_db: AsyncSession = Depends(get_db),
user: CurrentUserModel = Depends(LoginService.get_current_user),
):
data = await Sys_statisticsService.add_door_pass_count_services(query_db, user.user.user_name)
if data.is_success:
logger.info('门禁通行量次数加1成功')
return ResponseUtil.success(msg=data.message)
else:
logger.error('门禁通行量次数加1失败')
return ResponseUtil.error(msg=data.message)
# 访客引导次数加1
@sys_statisticsController.get(
'/add_visitor_guide_count'
)
async def add_visitor_guide_count(
request: Request,
query_db: AsyncSession = Depends(get_db),
user: CurrentUserModel = Depends(LoginService.get_current_user),
):
data = await Sys_statisticsService.add_visitor_guide_count_services(query_db, user.user.user_name)
if data.is_success:
logger.info('访客引导次数加1成功')
return ResponseUtil.success(msg=data.message)
else:
logger.error('访客引导次数加1失败')
return ResponseUtil.error(msg=data.message)
# 展厅讲解次数加1
@sys_statisticsController.get(
'/add_explain_count'
)
async def add_explain_count(
request: Request,
query_db: AsyncSession = Depends(get_db),
user: CurrentUserModel = Depends(LoginService.get_current_user),
):
data = await Sys_statisticsService.add_explain_count_services(query_db, user.user.user_name)
if data.is_success:
logger.info('展厅讲解次数加1成功')
return ResponseUtil.success(msg=data.message)
else:
logger.error('展厅讲解次数加1失败')
return ResponseUtil.error(msg=data.message)
# @sys_statisticsController.get(
# '/list', response_model=PageResponseModel
# # , dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:list'))]
# )
# async def get_system_sys_statistics_list(
# request: Request,
# sys_statistics_page_query: Sys_statisticsPageQueryModel = Depends(Sys_statisticsPageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# sys_statistics_page_query_result = await Sys_statisticsService.get_sys_statistics_list_services(query_db, sys_statistics_page_query, is_page=True)
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=sys_statistics_page_query_result)
# @sys_statisticsController.post(''
# , dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:add'))]
# )
# @ValidateFields(validate_model='add_sys_statistics')
# @Log(title='系统统计数据', business_type=BusinessType.INSERT)
# async def add_system_sys_statistics(
# request: Request,
# add_sys_statistics: Sys_statisticsModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_sys_statistics.create_time = datetime.now()
# add_sys_statistics.create_by = current_user.user.user_name
# add_sys_statistics.update_time = datetime.now()
# add_sys_statistics.update_by = current_user.user.user_name
# add_sys_statistics_result = await Sys_statisticsService.add_sys_statistics_services(query_db, add_sys_statistics)
# logger.info(add_sys_statistics_result.message)
#
# return ResponseUtil.success(msg=add_sys_statistics_result.message)
#
#
# @sys_statisticsController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:edit'))])
# @ValidateFields(validate_model='edit_sys_statistics')
# @Log(title='系统统计数据', business_type=BusinessType.UPDATE)
# async def edit_system_sys_statistics(
# request: Request,
# edit_sys_statistics: Sys_statisticsModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_sys_statistics.update_by = current_user.user.user_name
# edit_sys_statistics.update_time = datetime.now()
# edit_sys_statistics_result = await Sys_statisticsService.edit_sys_statistics_services(query_db, edit_sys_statistics)
# logger.info(edit_sys_statistics_result.message)
#
# return ResponseUtil.success(msg=edit_sys_statistics_result.message)
# @sys_statisticsController.delete('/{statistic_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:remove'))])
# @Log(title='系统统计数据', business_type=BusinessType.DELETE)
# async def delete_system_sys_statistics(request: Request, statistic_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_sys_statistics = DeleteSys_statisticsModel(statisticIds=statistic_ids)
# delete_sys_statistics_result = await Sys_statisticsService.delete_sys_statistics_services(query_db, delete_sys_statistics)
# logger.info(delete_sys_statistics_result.message)
#
# return ResponseUtil.success(msg=delete_sys_statistics_result.message)
#
#
# @sys_statisticsController.get(
# '/{statistic_id}', response_model=Sys_statisticsModel, dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:query'))]
# )
# async def query_detail_system_sys_statistics(request: Request, statistic_id: int, query_db: AsyncSession = Depends(get_db)):
# sys_statistics_detail_result = await Sys_statisticsService.sys_statistics_detail_services(query_db, statistic_id)
# logger.info(f'获取statistic_id为{statistic_id}的信息成功')
#
# return ResponseUtil.success(data=sys_statistics_detail_result)
#
#
# @sys_statisticsController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:sys_statistics:export'))])
# @Log(title='系统统计数据', business_type=BusinessType.EXPORT)
# async def export_system_sys_statistics_list(
# request: Request,
# sys_statistics_page_query: Sys_statisticsPageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# sys_statistics_query_result = await Sys_statisticsService.get_sys_statistics_list_services(query_db, sys_statistics_page_query, is_page=False)
# sys_statistics_export_result = await Sys_statisticsService.export_sys_statistics_list_services(sys_statistics_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(sys_statistics_export_result))

View File

@ -1,58 +0,0 @@
from fastapi import APIRouter, Body, Depends, Form, Request
from module_admin.service.login_service import LoginService
from module_admin.entity.vo.test_vo import TestUserName, TestPostForm, TestUserNamePage
from typing import List, Optional
from module_admin.service.test_service import TestService
from config.get_db import get_db
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.annotation.log_annotation import Log
from config.enums import BusinessType, RedisInitKeyConfig
from utils.response_util import ResponseUtil
from utils.log_util import logger
testController = APIRouter(prefix='/test')
@testController.get('/hello', response_model= List[TestUserName]
# ,dependencies=[Depends(LoginService.get_current_user)]
)
async def hello(request: Request,
name: Optional[str] = None,
query_db: AsyncSession = Depends(get_db), ):
print("名称", name)
user_name = await TestService.get_user_name(query_db,)
return user_name
@testController.post('/hello_post_json', response_model=str
,dependencies=[Depends(LoginService.get_current_user)]
)
@Log(title='测试Log', business_type=BusinessType.OTHER, log_type='operation')
async def hello_post_json(
request: Request,
login_info: TestUserNamePage,
query_db: AsyncSession = Depends(get_db)
):
print(login_info.user_name)
print(login_info.page_num)
print(login_info.page_size)
# print(login_info.password)
user_name = await TestService.get_user_name(query_db, login_info)
logger.info("测试成功")
return ResponseUtil.success(model_content=user_name)
@Log(title='测试post_form_data', business_type=BusinessType.OTHER, log_type='post')
@testController.post('/hello_post_form_data', response_model=str)
async def hello_post_form_data(
request: Request,
user_name: Optional[str] = Form(),
password: Optional[str] = Form()
):
print("*"*100)
print(user_name)
print(password)
return "success"

View File

@ -1,399 +0,0 @@
import os
from datetime import datetime
from fastapi import APIRouter, Depends, File, Form, Query, Request, UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
from typing import Literal, Optional, Union
from pydantic_validation_decorator import ValidateFields
from config.get_db import get_db
from config.enums import BusinessType
from config.env import UploadConfig
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.data_scope import GetDataScope
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.dept_vo import DeptModel
from module_admin.entity.vo.user_vo import (
AddUserModel,
CrudUserRoleModel,
CurrentUserModel,
DeleteUserModel,
EditUserModel,
ResetPasswordModel,
ResetUserModel,
UserDetailModel,
UserInfoModel,
UserModel,
UserPageQueryModel,
UserProfileModel,
UserRoleQueryModel,
UserRoleResponseModel,
)
from module_admin.service.login_service import LoginService
from module_admin.service.user_service import UserService
from module_admin.service.role_service import RoleService
from module_admin.service.dept_service import DeptService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.pwd_util import PwdUtil
from utils.response_util import ResponseUtil
from utils.upload_util import UploadUtil
userController = APIRouter(prefix='/system/user', dependencies=[Depends(LoginService.get_current_user)])
@userController.get('/deptTree', dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))])
async def get_system_dept_tree(
request: Request, query_db: AsyncSession = Depends(get_db), data_scope_sql: str = Depends(GetDataScope('SysDept'))
):
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(**{}), data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@userController.get(
'/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:list'))]
)
async def get_system_user_list(
request: Request,
user_page_query: UserPageQueryModel = Depends(UserPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
# 获取分页数据
user_page_query_result = await UserService.get_user_list_services(
query_db, user_page_query, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=user_page_query_result)
@userController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:add'))])
@ValidateFields(validate_model='add_user')
@Log(title='用户管理', business_type=BusinessType.INSERT)
async def add_system_user(
request: Request,
add_user: AddUserModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql)
await RoleService.check_role_data_scope_services(
query_db, ','.join([str(item) for item in add_user.role_ids]), role_data_scope_sql
)
add_user.password = PwdUtil.get_password_hash(add_user.password)
add_user.create_by = current_user.user.user_name
add_user.create_time = datetime.now()
add_user.update_by = current_user.user.user_name
add_user.update_time = datetime.now()
add_user_result = await UserService.add_user_services(query_db, add_user)
logger.info(add_user_result.message)
return ResponseUtil.success(msg=add_user_result.message)
@userController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))])
@ValidateFields(validate_model='edit_user')
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def edit_system_user(
request: Request,
edit_user: EditUserModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
await UserService.check_user_allowed_services(edit_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql)
await DeptService.check_dept_data_scope_services(query_db, edit_user.dept_id, dept_data_scope_sql)
await RoleService.check_role_data_scope_services(
query_db, ','.join([str(item) for item in edit_user.role_ids]), role_data_scope_sql
)
edit_user.update_by = current_user.user.user_name
edit_user.update_time = datetime.now()
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@userController.delete('/{user_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:user:remove'))])
@Log(title='用户管理', business_type=BusinessType.DELETE)
async def delete_system_user(
request: Request,
user_ids: str,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
user_id_list = user_ids.split(',') if user_ids else []
if user_id_list:
if current_user.user.user_id in list(map(int, user_id_list)):
logger.warning('当前登录用户不能删除')
return ResponseUtil.failure(msg='当前登录用户不能删除')
for user_id in user_id_list:
await UserService.check_user_allowed_services(UserModel(userId=int(user_id)))
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql)
delete_user = DeleteUserModel(userIds=user_ids, updateBy=current_user.user.user_name, updateTime=datetime.now())
delete_user_result = await UserService.delete_user_services(query_db, delete_user)
logger.info(delete_user_result.message)
return ResponseUtil.success(msg=delete_user_result.message)
@userController.put('/resetPwd', dependencies=[Depends(CheckUserInterfaceAuth('system:user:resetPwd'))])
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def reset_system_user_pwd(
request: Request,
reset_user: EditUserModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
await UserService.check_user_allowed_services(reset_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql)
edit_user = EditUserModel(
userId=reset_user.user_id,
password=PwdUtil.get_password_hash(reset_user.password),
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='pwd',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@userController.put('/changeStatus', dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))])
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def change_system_user_status(
request: Request,
change_user: EditUserModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
await UserService.check_user_allowed_services(change_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql)
edit_user = EditUserModel(
userId=change_user.user_id,
status=change_user.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@userController.get('/profile', response_model=UserProfileModel)
async def query_detail_system_user_profile(
request: Request,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id)
logger.info(f'获取user_id为{current_user.user.user_id}的信息成功')
return ResponseUtil.success(model_content=profile_user_result)
@userController.get(
'/{user_id}', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]
)
@userController.get(
'/', response_model=UserDetailModel, dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))]
)
async def query_detail_system_user(
request: Request,
user_id: Optional[Union[int, Literal['']]] = '',
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
if user_id and not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql)
detail_user_result = await UserService.user_detail_services(query_db, user_id)
logger.info(f'获取user_id为{user_id}的信息成功')
return ResponseUtil.success(model_content=detail_user_result)
@userController.post('/profile/avatar')
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_avatar(
request: Request,
avatarfile: bytes = File(),
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
if avatarfile:
relative_path = (
f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
)
dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path)
try:
os.makedirs(dir_path)
except FileExistsError:
pass
avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png'
avatar_path = os.path.join(dir_path, avatar_name)
with open(avatar_path, 'wb') as f:
f.write(avatarfile)
edit_user = EditUserModel(
userId=current_user.user.user_id,
avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}',
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='avatar',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(dict_content={'imgUrl': edit_user.avatar}, msg=edit_user_result.message)
return ResponseUtil.failure(msg='上传图片异常,请联系管理员')
@userController.put('/profile')
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_info(
request: Request,
user_info: UserInfoModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_user = EditUserModel(
**user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}),
userId=current_user.user.user_id,
userName=current_user.user.user_name,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [],
postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [],
role=current_user.user.role,
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@userController.put('/profile/updatePwd')
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def reset_system_user_password(
request: Request,
reset_password: ResetPasswordModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
reset_user = ResetUserModel(
userId=current_user.user.user_id,
oldPassword=reset_password.old_password,
password=reset_password.new_password,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
)
reset_user_result = await UserService.reset_user_services(query_db, reset_user)
logger.info(reset_user_result.message)
return ResponseUtil.success(msg=reset_user_result.message)
@userController.post('/importData', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))])
@Log(title='用户管理', business_type=BusinessType.IMPORT)
async def batch_import_system_user(
request: Request,
file: UploadFile = File(...),
update_support: bool = Query(alias='updateSupport'),
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
dept_data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
batch_import_result = await UserService.batch_import_user_services(
request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql
)
logger.info(batch_import_result.message)
return ResponseUtil.success(msg=batch_import_result.message)
@userController.post('/importTemplate', dependencies=[Depends(CheckUserInterfaceAuth('system:user:import'))])
async def export_system_user_template(request: Request, query_db: AsyncSession = Depends(get_db)):
user_import_template_result = await UserService.get_user_import_template_services()
logger.info('获取成功')
return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result))
@userController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:user:export'))])
@Log(title='用户管理', business_type=BusinessType.EXPORT)
async def export_system_user_list(
request: Request,
user_page_query: UserPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
data_scope_sql: str = Depends(GetDataScope('SysUser')),
):
# 获取全量数据
user_query_result = await UserService.get_user_list_services(
query_db, user_page_query, data_scope_sql, is_page=False
)
user_export_result = await UserService.export_user_list_services(user_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(user_export_result))
@userController.get(
'/authRole/{user_id}',
response_model=UserRoleResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('system:user:query'))],
)
async def get_system_allocated_role_list(request: Request, user_id: int, query_db: AsyncSession = Depends(get_db)):
user_role_query = UserRoleQueryModel(userId=user_id)
user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(
query_db, user_role_query
)
logger.info('获取成功')
return ResponseUtil.success(model_content=user_role_allocated_query_result)
@userController.put(
'/authRole',
response_model=UserRoleResponseModel,
dependencies=[Depends(CheckUserInterfaceAuth('system:user:edit'))],
)
@Log(title='用户管理', business_type=BusinessType.GRANT)
async def update_system_role_user(
request: Request,
user_id: int = Query(alias='userId'),
role_ids: str = Query(alias='roleIds'),
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
user_data_scope_sql: str = Depends(GetDataScope('SysUser')),
role_data_scope_sql: str = Depends(GetDataScope('SysDept')),
):
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql)
await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql)
add_user_role_result = await UserService.add_user_role_services(
query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)
)
logger.info(add_user_role_result.message)
return ResponseUtil.success(msg=add_user_role_result.message)

View File

@ -1,105 +0,0 @@
# from datetime import datetime
# from fastapi import APIRouter, Depends, Form, Request
# from pydantic_validation_decorator import ValidateFields
# from sqlalchemy.ext.asyncio import AsyncSession
# from config.enums import BusinessType
# from config.get_db import get_db
# from module_admin.annotation.log_annotation import Log
# from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
# from module_admin.entity.vo.user_vo import CurrentUserModel
# from module_admin.service.login_service import LoginService
# from module_admin.service.visitor_type_service import Visitor_typeService
# from module_admin.entity.vo.visitor_type_vo import DeleteVisitor_typeModel, Visitor_typeModel, Visitor_typePageQueryModel
# from utils.common_util import bytes2file_response
# from utils.log_util import logger
# from utils.page_util import PageResponseModel
# from utils.response_util import ResponseUtil
#
#
# visitor_typeController = APIRouter(prefix='/system/visitor_type', dependencies=[Depends(LoginService.get_current_user)])
#
#
# @visitor_typeController.get(
# '/list', response_model=PageResponseModel, dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:list'))]
# )
# async def get_system_visitor_type_list(
# request: Request,
# visitor_type_page_query: Visitor_typePageQueryModel = Depends(Visitor_typePageQueryModel.as_query),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取分页数据
# visitor_type_page_query_result = await Visitor_typeService.get_visitor_type_list_services(query_db, visitor_type_page_query, is_page=True)
# logger.info('获取成功')
#
# return ResponseUtil.success(model_content=visitor_type_page_query_result)
#
#
# @visitor_typeController.post('', dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:add'))])
# @ValidateFields(validate_model='add_visitor_type')
# @Log(title='访客类型', business_type=BusinessType.INSERT)
# async def add_system_visitor_type(
# request: Request,
# add_visitor_type: Visitor_typeModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_visitor_type.create_time = datetime.now()
# add_visitor_type.create_by = current_user.user.user_name
# add_visitor_type.update_time = datetime.now()
# add_visitor_type.update_by = current_user.user.user_name
# add_visitor_type_result = await Visitor_typeService.add_visitor_type_services(query_db, add_visitor_type)
# logger.info(add_visitor_type_result.message)
#
# return ResponseUtil.success(msg=add_visitor_type_result.message)
#
#
# @visitor_typeController.put('', dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:edit'))])
# @ValidateFields(validate_model='edit_visitor_type')
# @Log(title='访客类型', business_type=BusinessType.UPDATE)
# async def edit_system_visitor_type(
# request: Request,
# edit_visitor_type: Visitor_typeModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# edit_visitor_type.update_by = current_user.user.user_name
# edit_visitor_type.update_time = datetime.now()
# edit_visitor_type_result = await Visitor_typeService.edit_visitor_type_services(query_db, edit_visitor_type)
# logger.info(edit_visitor_type_result.message)
#
# return ResponseUtil.success(msg=edit_visitor_type_result.message)
#
#
# @visitor_typeController.delete('/{type_ids}', dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:remove'))])
# @Log(title='访客类型', business_type=BusinessType.DELETE)
# async def delete_system_visitor_type(request: Request, type_ids: str, query_db: AsyncSession = Depends(get_db)):
# delete_visitor_type = DeleteVisitor_typeModel(typeIds=type_ids)
# delete_visitor_type_result = await Visitor_typeService.delete_visitor_type_services(query_db, delete_visitor_type)
# logger.info(delete_visitor_type_result.message)
#
# return ResponseUtil.success(msg=delete_visitor_type_result.message)
#
#
# @visitor_typeController.get(
# '/{type_id}', response_model=Visitor_typeModel, dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:query'))]
# )
# async def query_detail_system_visitor_type(request: Request, type_id: int, query_db: AsyncSession = Depends(get_db)):
# visitor_type_detail_result = await Visitor_typeService.visitor_type_detail_services(query_db, type_id)
# logger.info(f'获取type_id为{type_id}的信息成功')
#
# return ResponseUtil.success(data=visitor_type_detail_result)
#
#
# @visitor_typeController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('system:visitor_type:export'))])
# @Log(title='访客类型', business_type=BusinessType.EXPORT)
# async def export_system_visitor_type_list(
# request: Request,
# visitor_type_page_query: Visitor_typePageQueryModel = Form(),
# query_db: AsyncSession = Depends(get_db),
# ):
# # 获取全量数据
# visitor_type_query_result = await Visitor_typeService.get_visitor_type_list_services(query_db, visitor_type_page_query, is_page=False)
# visitor_type_export_result = await Visitor_typeService.export_visitor_type_list_services(visitor_type_query_result)
# logger.info('导出成功')
#
# return ResponseUtil.streaming(data=bytes2file_response(visitor_type_export_result))

View File

@ -1,173 +0,0 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Form, Request
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from config.enums import BusinessType
from config.get_db import get_db
from module_admin.annotation.log_annotation import Log
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.login_service import LoginService
from module_admin.service.visitor_type_service import Visitor_typeService
from module_admin.service.words_service import WordsService
from module_admin.entity.vo.words_vo import DeleteWordsModel, WordsModel, WordsPageQueryModel, WordsUpdateModel
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.page_util import PageResponseModel
from utils.response_util import ResponseUtil
wordsController = APIRouter(prefix='/guide/words', dependencies=[Depends(LoginService.get_current_user)])
"""
访客记录: visitor:record:list, dependencies=[Depends(CheckUserInterfaceAuth('guide:words:list'))]
引导词管理: visitor:guide:list, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
"""
# 随机获取引导词
@wordsController.get('/random_words/{type}')
async def get_random_guide_word(request: Request, type: str, query_db: AsyncSession = Depends(get_db)):
guide_word = await WordsService.get_random_guide_word_services(query_db, type)
return ResponseUtil.success(data=guide_word)
@wordsController.post(
'/list', response_model=PageResponseModel
# , dependencies=[Depends(CheckUserInterfaceAuth('guide:words:list'))]
, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
)
async def get_guide_words_list(
request: Request,
words_page_query: WordsPageQueryModel = Depends(WordsPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
print(words_page_query.begin_time)
print(words_page_query.end_time)
# 获取分页数据
words_page_query_result = await WordsService.get_words_list_services(query_db, words_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=words_page_query_result)
#批量启用引导词
@wordsController.post('/enable_guide/{guide_ids}', dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))])
async def enable_guide(
request: Request,
guide_ids: str,
query_db: AsyncSession = Depends(get_db),
):
edit_del_result = await WordsService.edit_del_words_services(query_db=query_db, guide_ids=guide_ids, del_flg='0')
return ResponseUtil.success(msg=edit_del_result.message)
#批量禁用引导词
@wordsController.post('/disable_guide/{guide_ids}', dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))])
async def disable_guide(
request: Request,
guide_ids: str,
query_db: AsyncSession = Depends(get_db),
):
edit_del_result = await WordsService.edit_del_words_services(query_db=query_db, guide_ids=guide_ids, del_flg='2')
return ResponseUtil.success(msg=edit_del_result.message)
#获取访客类型列表
@wordsController.get('/visitor_type_list',)
async def get_system_visitor_type_list(
request: Request,
query_db: AsyncSession = Depends(get_db),
):
visitor_type_list = await Visitor_typeService.get_system_visitor_type_list(query_db=query_db)
return ResponseUtil.success(data=visitor_type_list)
@wordsController.post('/add_guide'
# , dependencies=[Depends(CheckUserInterfaceAuth('guide:words:add'))]
, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
)
@ValidateFields(validate_model='add_words')
@Log(title='引导词', business_type=BusinessType.INSERT)
async def add_guide_words(
request: Request,
add_words: WordsModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
if add_words.type is None:
return ResponseUtil.failure(msg='引导词类型不能为空')
if add_words.text is None:
return ResponseUtil.failure(msg='引导词内容不能为空')
add_words.create_time = datetime.now()
add_words.update_time = datetime.now()
add_words.create_by = current_user.user.user_name
add_words.del_flag = "0"
add_words_result = await WordsService.add_words_services(query_db, add_words)
logger.info(add_words_result.message)
return ResponseUtil.success(msg=add_words_result.message)
@wordsController.put('/edit_guide'
# ,dependencies=[Depends(CheckUserInterfaceAuth('guide:words:edit'))]
, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
)
@ValidateFields(validate_model='edit_words')
@Log(title='引导词', business_type=BusinessType.UPDATE)
async def edit_guide_words(
request: Request,
edit_words: WordsUpdateModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_words.update_by = current_user.user.user_name
edit_words.update_time = datetime.now()
edit_words_result = await WordsService.edit_words_services(query_db, edit_words)
logger.info(edit_words_result.message)
return ResponseUtil.success(msg=edit_words_result.message)
@wordsController.delete('/{guide_ids}'
# , dependencies=[Depends(CheckUserInterfaceAuth('guide:words:remove'))]
, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
)
@Log(title='引导词', business_type=BusinessType.DELETE)
async def delete_guide_words(request: Request, guide_ids: str, query_db: AsyncSession = Depends(get_db)):
delete_words = DeleteWordsModel(guideIds=guide_ids)
delete_words_result = await WordsService.delete_words_services(query_db, delete_words)
logger.info(delete_words_result.message)
return ResponseUtil.success(msg=delete_words_result.message)
@wordsController.get(
'/{guide_id}', response_model=WordsModel
# , dependencies=[Depends(CheckUserInterfaceAuth('guide:words:query'))]
, dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))]
)
async def query_detail_guide_words(request: Request, guide_id: int, query_db: AsyncSession = Depends(get_db)):
words_detail_result = await WordsService.words_detail_services(query_db, guide_id)
logger.info(f'获取guide_id为{guide_id}的信息成功')
return ResponseUtil.success(data=words_detail_result)
@wordsController.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('visitor:guide:list'))])
@Log(title='引导词', business_type=BusinessType.EXPORT)
async def export_guide_words_list(
request: Request,
words_page_query: WordsPageQueryModel = Form(),
query_db: AsyncSession = Depends(get_db),
):
# 获取全量数据
words_query_result = await WordsService.get_words_list_services(query_db, words_page_query, is_page=False)
words_export_result = await WordsService.export_words_list_services(words_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(words_export_result))

View File

@ -1,116 +0,0 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.config_do import SysConfig
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel
from utils.page_util import PageUtil
class ConfigDao:
"""
参数配置管理模块数据库操作层
"""
@classmethod
async def get_config_detail_by_id(cls, db: AsyncSession, config_id: int):
"""
根据参数配置id获取参数配置详细信息
:param db: orm对象
:param config_id: 参数配置id
:return: 参数配置信息对象
"""
config_info = (await db.execute(select(SysConfig).where(SysConfig.config_id == config_id))).scalars().first()
return config_info
@classmethod
async def get_config_detail_by_info(cls, db: AsyncSession, config: ConfigModel):
"""
根据参数配置参数获取参数配置信息
:param db: orm对象
:param config: 参数配置参数对象
:return: 参数配置信息对象
"""
config_info = (
(
await db.execute(
select(SysConfig).where(
SysConfig.config_key == config.config_key if config.config_key else True,
SysConfig.config_value == config.config_value if config.config_value else True,
)
)
)
.scalars()
.first()
)
return config_info
@classmethod
async def get_config_list(cls, db: AsyncSession, query_object: ConfigPageQueryModel, is_page: bool = False):
"""
根据查询参数获取参数配置列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 参数配置列表信息对象
"""
query = (
select(SysConfig)
.where(
SysConfig.config_name.like(f'%{query_object.config_name}%') if query_object.config_name else True,
SysConfig.config_key.like(f'%{query_object.config_key}%') if query_object.config_key else True,
SysConfig.config_type == query_object.config_type if query_object.config_type else True,
SysConfig.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_time and query_object.end_time
else True,
)
.order_by(SysConfig.config_id)
.distinct()
)
config_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return config_list
@classmethod
async def add_config_dao(cls, db: AsyncSession, config: ConfigModel):
"""
新增参数配置数据库操作
:param db: orm对象
:param config: 参数配置对象
:return:
"""
db_config = SysConfig(**config.model_dump())
db.add(db_config)
await db.flush()
return db_config
@classmethod
async def edit_config_dao(cls, db: AsyncSession, config: dict):
"""
编辑参数配置数据库操作
:param db: orm对象
:param config: 需要更新的参数配置字典
:return:
"""
await db.execute(update(SysConfig), [config])
@classmethod
async def delete_config_dao(cls, db: AsyncSession, config: ConfigModel):
"""
删除参数配置数据库操作
:param db: orm对象
:param config: 参数配置对象
:return:
"""
await db.execute(delete(SysConfig).where(SysConfig.config_id.in_([config.config_id])))

View File

@ -1,307 +0,0 @@
from sqlalchemy import bindparam, func, or_, select, update # noqa: F401
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.util import immutabledict
from typing import List
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.do.role_do import SysRoleDept # noqa: F401
from module_admin.entity.do.user_do import SysUser
from module_admin.entity.vo.dept_vo import DeptModel
class DeptDao:
"""
部门管理模块数据库操作层
"""
@classmethod
async def get_dept_by_id(cls, db: AsyncSession, dept_id: int):
"""
根据部门id获取在用部门信息
:param db: orm对象
:param dept_id: 部门id
:return: 在用部门信息对象
"""
dept_info = (await db.execute(select(SysDept).where(SysDept.dept_id == dept_id))).scalars().first()
return dept_info
@classmethod
async def get_dept_detail_by_id(cls, db: AsyncSession, dept_id: int):
"""
根据部门id获取部门详细信息
:param db: orm对象
:param dept_id: 部门id
:return: 部门信息对象
"""
dept_info = (
(await db.execute(select(SysDept).where(SysDept.dept_id == dept_id, SysDept.del_flag == '0')))
.scalars()
.first()
)
return dept_info
@classmethod
async def get_dept_detail_by_info(cls, db: AsyncSession, dept: DeptModel):
"""
根据部门参数获取部门信息
:param db: orm对象
:param dept: 部门参数对象
:return: 部门信息对象
"""
dept_info = (
(
await db.execute(
select(SysDept).where(
SysDept.parent_id == dept.parent_id if dept.parent_id else True,
SysDept.dept_name == dept.dept_name if dept.dept_name else True,
)
)
)
.scalars()
.first()
)
return dept_info
@classmethod
async def get_dept_info_for_edit_option(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str):
"""
获取部门编辑对应的在用部门列表信息
:param db: orm对象
:param dept_info: 部门对象
:param data_scope_sql: 数据权限对应的查询sql语句
:return: 部门列表信息
"""
dept_result = (
(
await db.execute(
select(SysDept)
.where(
SysDept.dept_id != dept_info.dept_id,
~SysDept.dept_id.in_(
select(SysDept.dept_id).where(func.find_in_set(dept_info.dept_id, SysDept.ancestors))
),
SysDept.del_flag == '0',
SysDept.status == '0',
eval(data_scope_sql),
)
.order_by(SysDept.order_num)
.distinct()
)
)
.scalars()
.all()
)
return dept_result
@classmethod
async def get_children_dept_dao(cls, db: AsyncSession, dept_id: int):
"""
根据部门id查询当前部门的子部门列表信息
:param db: orm对象
:param dept_id: 部门id
:return: 子部门信息列表
"""
dept_result = (
(await db.execute(select(SysDept).where(func.find_in_set(dept_id, SysDept.ancestors)))).scalars().all()
)
return dept_result
@classmethod
async def get_dept_list_for_tree(cls, db: AsyncSession, dept_info: DeptModel, data_scope_sql: str):
"""
获取所有在用部门列表信息
:param db: orm对象
:param dept_info: 部门对象
:param data_scope_sql: 数据权限对应的查询sql语句
:return: 在用部门列表信息
"""
dept_result = (
(
await db.execute(
select(SysDept)
.where(
SysDept.status == '0',
SysDept.del_flag == '0',
SysDept.dept_name.like(f'%{dept_info.dept_name}%') if dept_info.dept_name else True,
eval(data_scope_sql),
)
.order_by(SysDept.order_num)
.distinct()
)
)
.scalars()
.all()
)
return dept_result
@classmethod
async def get_dept_list(cls, db: AsyncSession, page_object: DeptModel, data_scope_sql: str):
"""
根据查询参数获取部门列表信息
:param db: orm对象
:param page_object: 不分页查询参数对象
:param data_scope_sql: 数据权限对应的查询sql语句
:return: 部门列表信息对象
"""
dept_result = (
(
await db.execute(
select(SysDept)
.where(
SysDept.del_flag == '0',
SysDept.dept_id == page_object.dept_id if page_object.dept_id is not None else True,
SysDept.status == page_object.status if page_object.status else True,
SysDept.dept_name.like(f'%{page_object.dept_name}%') if page_object.dept_name else True,
eval(data_scope_sql),
)
.order_by(SysDept.order_num)
.distinct()
)
)
.scalars()
.all()
)
return dept_result
@classmethod
async def add_dept_dao(cls, db: AsyncSession, dept: DeptModel):
"""
新增部门数据库操作
:param db: orm对象
:param dept: 部门对象
:return: 新增校验结果
"""
db_dept = SysDept(**dept.model_dump())
db.add(db_dept)
await db.flush()
return db_dept
@classmethod
async def edit_dept_dao(cls, db: AsyncSession, dept: dict):
"""
编辑部门数据库操作
:param db: orm对象
:param dept: 需要更新的部门字典
:return: 编辑校验结果
"""
await db.execute(update(SysDept), [dept])
@classmethod
async def update_dept_children_dao(cls, db: AsyncSession, update_dept: List):
"""
更新子部门信息
:param db: orm对象
:param update_dept: 需要更新的部门列表
:return:
"""
await db.execute(
update(SysDept)
.where(SysDept.dept_id == bindparam('dept_id'))
.values(
{
'dept_id': bindparam('dept_id'),
'ancestors': bindparam('ancestors'),
}
),
update_dept,
execution_options=immutabledict({'synchronize_session': None}),
)
@classmethod
async def update_dept_status_normal_dao(cls, db: AsyncSession, dept_id_list: List):
"""
批量更新部门状态为正常
:param db: orm对象
:param dept_id_list: 部门id列表
:return:
"""
await db.execute(update(SysDept).where(SysDept.dept_id.in_(dept_id_list)).values(status='0'))
@classmethod
async def delete_dept_dao(cls, db: AsyncSession, dept: DeptModel):
"""
删除部门数据库操作
:param db: orm对象
:param dept: 部门对象
:return:
"""
await db.execute(
update(SysDept)
.where(SysDept.dept_id == dept.dept_id)
.values(del_flag='2', update_by=dept.update_by, update_time=dept.update_time)
)
@classmethod
async def count_normal_children_dept_dao(cls, db: AsyncSession, dept_id: int):
"""
根据部门id查询查询所有子部门正常状态的数量
:param db: orm对象
:param dept_id: 部门id
:return: 所有子部门正常状态的数量
"""
normal_children_dept_count = (
await db.execute(
select(func.count('*'))
.select_from(SysDept)
.where(SysDept.status == '0', SysDept.del_flag == '0', func.find_in_set(dept_id, SysDept.ancestors))
)
).scalar()
return normal_children_dept_count
@classmethod
async def count_children_dept_dao(cls, db: AsyncSession, dept_id: int):
"""
根据部门id查询查询所有子部门所有状态的数量
:param db: orm对象
:param dept_id: 部门id
:return: 所有子部门所有状态的数量
"""
children_dept_count = (
await db.execute(
select(func.count('*'))
.select_from(SysDept)
.where(SysDept.del_flag == '0', SysDept.parent_id == dept_id)
.limit(1)
)
).scalar()
return children_dept_count
@classmethod
async def count_dept_user_dao(cls, db: AsyncSession, dept_id: int):
"""
根据部门id查询查询部门下的用户数量
:param db: orm对象
:param dept_id: 部门id
:return: 部门下的用户数量
"""
dept_user_count = (
await db.execute(
select(func.count('*')).select_from(SysUser).where(SysUser.dept_id == dept_id, SysUser.del_flag == '0')
)
).scalar()
return dept_user_count

View File

@ -1,281 +0,0 @@
from datetime import datetime, time
from sqlalchemy import and_, delete, func, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.dict_do import SysDictType, SysDictData
from module_admin.entity.vo.dict_vo import DictDataModel, DictDataPageQueryModel, DictTypeModel, DictTypePageQueryModel
from utils.page_util import PageUtil
from utils.time_format_util import list_format_datetime
class DictTypeDao:
"""
字典类型管理模块数据库操作层
"""
@classmethod
async def get_dict_type_detail_by_id(cls, db: AsyncSession, dict_id: int):
"""
根据字典类型id获取字典类型详细信息
:param db: orm对象
:param dict_id: 字典类型id
:return: 字典类型信息对象
"""
dict_type_info = (await db.execute(select(SysDictType).where(SysDictType.dict_id == dict_id))).scalars().first()
return dict_type_info
@classmethod
async def get_dict_type_detail_by_info(cls, db: AsyncSession, dict_type: DictTypeModel):
"""
根据字典类型参数获取字典类型信息
:param db: orm对象
:param dict_type: 字典类型参数对象
:return: 字典类型信息对象
"""
dict_type_info = (
(
await db.execute(
select(SysDictType).where(
SysDictType.dict_type == dict_type.dict_type if dict_type.dict_type else True,
SysDictType.dict_name == dict_type.dict_name if dict_type.dict_name else True,
)
)
)
.scalars()
.first()
)
return dict_type_info
@classmethod
async def get_all_dict_type(cls, db: AsyncSession):
"""
获取所有的字典类型信息
:param db: orm对象
:return: 字典类型信息列表对象
"""
dict_type_info = (await db.execute(select(SysDictType))).scalars().all()
return list_format_datetime(dict_type_info)
@classmethod
async def get_dict_type_list(cls, db: AsyncSession, query_object: DictTypePageQueryModel, is_page: bool = False):
"""
根据查询参数获取字典类型列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 字典类型列表信息对象
"""
query = (
select(SysDictType)
.where(
SysDictType.dict_name.like(f'%{query_object.dict_name}%') if query_object.dict_name else True,
SysDictType.dict_type.like(f'%{query_object.dict_type}%') if query_object.dict_type else True,
SysDictType.status == query_object.status if query_object.status else True,
SysDictType.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_time and query_object.end_time
else True,
)
.order_by(SysDictType.dict_id)
.distinct()
)
dict_type_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return dict_type_list
@classmethod
async def add_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel):
"""
新增字典类型数据库操作
:param db: orm对象
:param dict_type: 字典类型对象
:return:
"""
db_dict_type = SysDictType(**dict_type.model_dump())
db.add(db_dict_type)
await db.flush()
return db_dict_type
@classmethod
async def edit_dict_type_dao(cls, db: AsyncSession, dict_type: dict):
"""
编辑字典类型数据库操作
:param db: orm对象
:param dict_type: 需要更新的字典类型字典
:return:
"""
await db.execute(update(SysDictType), [dict_type])
@classmethod
async def delete_dict_type_dao(cls, db: AsyncSession, dict_type: DictTypeModel):
"""
删除字典类型数据库操作
:param db: orm对象
:param dict_type: 字典类型对象
:return:
"""
await db.execute(delete(SysDictType).where(SysDictType.dict_id.in_([dict_type.dict_id])))
class DictDataDao:
"""
字典数据管理模块数据库操作层
"""
@classmethod
async def get_dict_data_detail_by_id(cls, db: AsyncSession, dict_code: int):
"""
根据字典数据id获取字典数据详细信息
:param db: orm对象
:param dict_code: 字典数据id
:return: 字典数据信息对象
"""
dict_data_info = (
(await db.execute(select(SysDictData).where(SysDictData.dict_code == dict_code))).scalars().first()
)
return dict_data_info
@classmethod
async def get_dict_data_detail_by_info(cls, db: AsyncSession, dict_data: DictDataModel):
"""
根据字典数据参数获取字典数据信息
:param db: orm对象
:param dict_data: 字典数据参数对象
:return: 字典数据信息对象
"""
dict_data_info = (
(
await db.execute(
select(SysDictData).where(
SysDictData.dict_type == dict_data.dict_type,
SysDictData.dict_label == dict_data.dict_label,
SysDictData.dict_value == dict_data.dict_value,
)
)
)
.scalars()
.first()
)
return dict_data_info
@classmethod
async def get_dict_data_list(cls, db: AsyncSession, query_object: DictDataPageQueryModel, is_page: bool = False):
"""
根据查询参数获取字典数据列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 字典数据列表信息对象
"""
query = (
select(SysDictData)
.where(
SysDictData.dict_type == query_object.dict_type if query_object.dict_type else True,
SysDictData.dict_label.like(f'%{query_object.dict_label}%') if query_object.dict_label else True,
SysDictData.status == query_object.status if query_object.status else True,
)
.order_by(SysDictData.dict_sort)
.distinct()
)
dict_data_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return dict_data_list
@classmethod
async def query_dict_data_list(cls, db: AsyncSession, dict_type: str):
"""
根据查询参数获取字典数据列表信息
:param db: orm对象
:param dict_type: 字典类型
:return: 字典数据列表信息对象
"""
dict_data_list = (
(
await db.execute(
select(SysDictData)
.select_from(SysDictType)
.where(SysDictType.dict_type == dict_type if dict_type else True, SysDictType.status == '0')
.join(
SysDictData,
and_(SysDictType.dict_type == SysDictData.dict_type, SysDictData.status == '0'),
isouter=True,
)
.order_by(SysDictData.dict_sort)
.distinct()
)
)
.scalars()
.all()
)
return dict_data_list
@classmethod
async def add_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel):
"""
新增字典数据数据库操作
:param db: orm对象
:param dict_data: 字典数据对象
:return:
"""
db_data_type = SysDictData(**dict_data.model_dump())
db.add(db_data_type)
await db.flush()
return db_data_type
@classmethod
async def edit_dict_data_dao(cls, db: AsyncSession, dict_data: dict):
"""
编辑字典数据数据库操作
:param db: orm对象
:param dict_data: 需要更新的字典数据字典
:return:
"""
await db.execute(update(SysDictData), [dict_data])
@classmethod
async def delete_dict_data_dao(cls, db: AsyncSession, dict_data: DictDataModel):
"""
删除字典数据数据库操作
:param db: orm对象
:param dict_data: 字典数据对象
:return:
"""
await db.execute(delete(SysDictData).where(SysDictData.dict_code.in_([dict_data.dict_code])))
@classmethod
async def count_dict_data_dao(cls, db: AsyncSession, dict_type: str):
"""
根据字典类型查询字典类型关联的字典数据数量
:param db: orm对象
:param dict_type: 字典类型
:return: 字典类型关联的字典数据数量
"""
dict_data_count = (
await db.execute(select(func.count('*')).select_from(SysDictData).where(SysDictData.dict_type == dict_type))
).scalar()
return dict_data_count

View File

@ -1,154 +0,0 @@
from sqlalchemy import delete, select, update, or_
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.door_do import Door
from module_admin.entity.vo.door_vo import DoorModel, DoorPageQueryModel
from utils.page_util import PageUtil
class DoorDao:
"""
门禁设备模块数据库操作层
"""
@classmethod
async def get_door_door_status(cls, db: AsyncSession):
"""获取门禁状态
"""
stmt = (
select(Door.indexCode, Door.name).select_from(Door).where(Door.permission=="1")
)
result = await db.execute(stmt)
return result.mappings().all()
@classmethod
async def get_door_index_code_list(cls, db: AsyncSession, permission: str = None):
"""
获取门禁设备索引编码列表
"""
query = select(Door.indexCode).where(Door.permission == permission if permission else True)
result = await db.execute(query)
return [row[0] for row in result.all()]
@classmethod
async def get_door_detail_by_id(cls, db: AsyncSession, id: int):
"""
根据主键自增获取门禁设备详细信息
:param db: orm对象
:param id: 主键自增
:return: 门禁设备信息对象
"""
door_info = (
(
await db.execute(
select(Door)
.where(
Door.id == id
)
)
)
.scalars()
.first()
)
return door_info
@classmethod
async def get_door_detail_by_info(cls, db: AsyncSession, door: DoorModel):
"""
根据门禁设备参数获取门禁设备信息
:param db: orm对象
:param door: 门禁设备参数对象
:return: 门禁设备信息对象
"""
door_info = (
(
await db.execute(
select(Door).where(
)
)
)
.scalars()
.first()
)
return door_info
@classmethod
async def get_door_list(cls, db: AsyncSession, query_object: DoorPageQueryModel, is_page: bool = False):
"""
根据查询参数获取门禁设备列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 门禁设备列表信息对象
"""
query = (
select(Door)
.where(
# Door.index_code == query_object.index_code if query_object.index_code else True,
or_(
(
Door.name.like(f"%{query_object.key_word}%")
if query_object.key_word
else True
),
(
Door.install_location.like(f"%{query_object.key_word}%")
if query_object.key_word
else True
),
),
# Door.status == query_object.status if query_object.status else True,
(
Door.permission == query_object.permission
if query_object.permission
else True
),
)
.order_by(Door.id)
.distinct()
)
door_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return door_list
@classmethod
async def add_door_dao(cls, db: AsyncSession, door: DoorModel):
"""
新增门禁设备数据库操作
:param db: orm对象
:param door: 门禁设备对象
:return:
"""
db_door = Door(**door.model_dump(exclude={}))
db.add(db_door)
await db.flush()
return db_door
@classmethod
async def edit_door_dao(cls, db: AsyncSession, door: dict):
"""
编辑门禁设备数据库操作
:param db: orm对象
:param door: 需要更新的门禁设备字典
:return:
"""
await db.execute(update(Door), [door])
@classmethod
async def delete_door_dao(cls, db: AsyncSession, door: DoorModel):
"""
删除门禁设备数据库操作
:param db: orm对象
:param door: 门禁设备对象
:return:
"""
await db.execute(delete(Door).where(Door.id.in_([door.id])))

View File

@ -1,135 +0,0 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update, desc
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.explanation_content_do import ExplanationContent
from module_admin.entity.vo.explanation_content_vo import Explanation_contentModel, Explanation_contentPageQueryModel
from utils.page_util import PageUtil
class Explanation_contentDao:
"""
讲解内容模块数据库操作层
"""
@classmethod
async def get_explanation_content_detail_by_id(cls, db: AsyncSession, explanation_content_id: int):
"""
根据主键ID获取讲解内容详细信息
:param db: orm对象
:param explanation_content_id: 主键ID
:return: 讲解内容信息对象
"""
explanation_content_info = (
(
await db.execute(
select(ExplanationContent)
.where(
ExplanationContent.explanation_content_id == explanation_content_id
)
)
)
.scalars()
.first()
)
return explanation_content_info
@classmethod
async def get_explanation_content_detail_by_info(cls, db: AsyncSession, explanation_content: Explanation_contentModel):
"""
根据讲解内容参数获取讲解内容信息
:param db: orm对象
:param explanation_content: 讲解内容参数对象
:return: 讲解内容信息对象
"""
explanation_content_info = (
(
await db.execute(
select(ExplanationContent).where(
)
)
)
.scalars()
.first()
)
return explanation_content_info
@classmethod
async def get_explanation_content_list(cls, db: AsyncSession, query_object: Explanation_contentPageQueryModel, is_page: bool = False):
"""
根据查询参数获取讲解内容列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 讲解内容列表信息对象
"""
query = (
select(ExplanationContent)
.where(
# ExplanationContent.title == query_object.title if query_object.title else True,
# ExplanationContent.content == query_object.content if query_object.content else True,
ExplanationContent.type == query_object.type if query_object.type else True,
# ExplanationContent.spend_time == query_object.spend_time if query_object.spend_time else True,
ExplanationContent.language == query_object.language if query_object.language else True,
ExplanationContent.status == query_object.status if query_object.status else True,
ExplanationContent.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_create_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_create_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_create_time and query_object.end_create_time
else True,
ExplanationContent.update_time.between(
datetime.combine(datetime.strptime(query_object.begin_update_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_update_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_update_time and query_object.end_update_time
else True,
)
.order_by(desc(ExplanationContent.update_time))
.distinct()
)
explanation_content_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return explanation_content_list
@classmethod
async def add_explanation_content_dao(cls, db: AsyncSession, explanation_content: Explanation_contentModel):
"""
新增讲解内容数据库操作
:param db: orm对象
:param explanation_content: 讲解内容对象
:return:
"""
db_explanation_content = ExplanationContent(**explanation_content.model_dump(exclude={}))
db.add(db_explanation_content)
await db.flush()
return db_explanation_content
@classmethod
async def edit_explanation_content_dao(cls, db: AsyncSession, explanation_content: dict):
"""
编辑讲解内容数据库操作
:param db: orm对象
:param explanation_content: 需要更新的讲解内容字典
:return:
"""
await db.execute(update(ExplanationContent), [explanation_content])
@classmethod
async def delete_explanation_content_dao(cls, db: AsyncSession, explanation_content: Explanation_contentModel):
"""
删除讲解内容数据库操作
:param db: orm对象
:param explanation_content: 讲解内容对象
:return:
"""
await db.execute(delete(ExplanationContent).where(ExplanationContent.explanation_content_id.in_([explanation_content.explanation_content_id])))

View File

@ -1,120 +0,0 @@
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.explanation_content_type_do import ExplanationContentType
from module_admin.entity.vo.explanation_content_type_vo import Explanation_content_typeModel, Explanation_content_typePageQueryModel
from utils.page_util import PageUtil
class Explanation_content_typeDao:
"""
讲解内容类型模块数据库操作层
"""
@classmethod
async def get_explanation_content_type_detail_by_id(cls, db: AsyncSession, content_type_id: int):
"""
根据主键ID获取讲解内容类型详细信息
:param db: orm对象
:param content_type_id: 主键ID
:return: 讲解内容类型信息对象
"""
explanation_content_type_info = (
(
await db.execute(
select(ExplanationContentType)
.where(
ExplanationContentType.content_type_id == content_type_id
)
)
)
.scalars()
.first()
)
return explanation_content_type_info
@classmethod
async def get_explanation_content_type_detail_by_info(cls, db: AsyncSession, explanation_content_type: Explanation_content_typeModel):
"""
根据讲解内容类型参数获取讲解内容类型信息
:param db: orm对象
:param explanation_content_type: 讲解内容类型参数对象
:return: 讲解内容类型信息对象
"""
explanation_content_type_info = (
(
await db.execute(
select(ExplanationContentType).where(
)
)
)
.scalars()
.first()
)
return explanation_content_type_info
@classmethod
async def get_explanation_content_type_list(cls, db: AsyncSession, query_object: Explanation_content_typePageQueryModel, is_page: bool = False):
"""
根据查询参数获取讲解内容类型列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 讲解内容类型列表信息对象
"""
query = (
select(ExplanationContentType)
.where(
ExplanationContentType.name.like(f'%{query_object.name}%') if query_object.name else True,
ExplanationContentType.type_value == query_object.type_value if query_object.type_value else True,
ExplanationContentType.create_time.like(f'%{query_object.create_time}%') if query_object.create_time else True,
ExplanationContentType.update_time.like(f'%{query_object.update_time}%') if query_object.update_time else True,
)
.order_by(ExplanationContentType.content_type_id)
.distinct()
)
# explanation_content_type_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
explanation_content_type_list = (await db.execute(query)).scalars().all()
return explanation_content_type_list
@classmethod
async def add_explanation_content_type_dao(cls, db: AsyncSession, explanation_content_type: Explanation_content_typeModel):
"""
新增讲解内容类型数据库操作
:param db: orm对象
:param explanation_content_type: 讲解内容类型对象
:return:
"""
db_explanation_content_type = ExplanationContentType(**explanation_content_type.model_dump(exclude={}))
db.add(db_explanation_content_type)
await db.flush()
return db_explanation_content_type
@classmethod
async def edit_explanation_content_type_dao(cls, db: AsyncSession, explanation_content_type: dict):
"""
编辑讲解内容类型数据库操作
:param db: orm对象
:param explanation_content_type: 需要更新的讲解内容类型字典
:return:
"""
await db.execute(update(ExplanationContentType), [explanation_content_type])
@classmethod
async def delete_explanation_content_type_dao(cls, db: AsyncSession, explanation_content_type: Explanation_content_typeModel):
"""
删除讲解内容类型数据库操作
:param db: orm对象
:param explanation_content_type: 讲解内容类型对象
:return:
"""
await db.execute(delete(ExplanationContentType).where(ExplanationContentType.content_type_id.in_([explanation_content_type.content_type_id])))

View File

@ -1,131 +0,0 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.explanation_style_do import ExplanationStyle
from module_admin.entity.vo.explanation_style_vo import Explanation_styleModel, Explanation_stylePageQueryModel
from utils.page_util import PageUtil
class Explanation_styleDao:
"""
讲解风格模块数据库操作层
"""
@classmethod
async def get_explanation_style_detail_by_id(cls, db: AsyncSession, explanation_style_id: int):
"""
根据主键ID获取讲解风格详细信息
:param db: orm对象
:param explanation_style_id: 主键ID
:return: 讲解风格信息对象
"""
explanation_style_info = (
(
await db.execute(
select(ExplanationStyle)
.where(
ExplanationStyle.explanation_style_id == explanation_style_id
)
)
)
.scalars()
.first()
)
return explanation_style_info
@classmethod
async def get_explanation_style_detail_by_info(cls, db: AsyncSession, explanation_style: Explanation_styleModel):
"""
根据讲解风格参数获取讲解风格信息
:param db: orm对象
:param explanation_style: 讲解风格参数对象
:return: 讲解风格信息对象
"""
explanation_style_info = (
(
await db.execute(
select(ExplanationStyle).where(
)
)
)
.scalars()
.first()
)
return explanation_style_info
@classmethod
async def get_explanation_style_list(cls, db: AsyncSession, query_object: Explanation_stylePageQueryModel, is_page: bool = False):
"""
根据查询参数获取讲解风格列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 讲解风格列表信息对象
"""
query = (
select(ExplanationStyle)
.where(
ExplanationStyle.name.like(f'%{query_object.name}%') if query_object.name else True,
ExplanationStyle.detail == query_object.detail if query_object.detail else True,
ExplanationStyle.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_create_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_create_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_create_time and query_object.end_create_time
else True,
ExplanationStyle.update_time.between(
datetime.combine(datetime.strptime(query_object.begin_update_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_update_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_update_time and query_object.end_update_time
else True,
)
.order_by(ExplanationStyle.explanation_style_id)
.distinct()
)
explanation_style_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return explanation_style_list
@classmethod
async def add_explanation_style_dao(cls, db: AsyncSession, explanation_style: Explanation_styleModel):
"""
新增讲解风格数据库操作
:param db: orm对象
:param explanation_style: 讲解风格对象
:return:
"""
db_explanation_style = ExplanationStyle(**explanation_style.model_dump(exclude={}))
db.add(db_explanation_style)
await db.flush()
return db_explanation_style
@classmethod
async def edit_explanation_style_dao(cls, db: AsyncSession, explanation_style: dict):
"""
编辑讲解风格数据库操作
:param db: orm对象
:param explanation_style: 需要更新的讲解风格字典
:return:
"""
await db.execute(update(ExplanationStyle), [explanation_style])
@classmethod
async def delete_explanation_style_dao(cls, db: AsyncSession, explanation_style: Explanation_styleModel):
"""
删除讲解风格数据库操作
:param db: orm对象
:param explanation_style: 讲解风格对象
:return:
"""
await db.execute(delete(ExplanationStyle).where(ExplanationStyle.explanation_style_id.in_([explanation_style.explanation_style_id])))

View File

@ -1,194 +0,0 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.explanation_style_do import ExplanationStyle
from module_admin.entity.do.explanation_style_robot_pair_do import ExplanationStyleRobotPairing
from module_admin.entity.do.explanation_style_do import ExplanationStyle
from module_admin.entity.vo.explanation_style_robot_pair_vo import Explanation_style_robot_pairModel, \
Explanation_style_robot_pairPageQueryModel, SwitchExplanationStyleModel
from utils.page_util import PageUtil
class Explanation_style_robot_pairDao:
"""
讲解风格--机器人配对模块数据库操作层
"""
@classmethod
async def get_robot_role_style(cls, db: AsyncSession, robot_id: int, role_id: int):
"""根据机器人id和角色id获取机器人角色样式
Args:
db (AsyncSession): 数据库会话
robot_id (int): 机器人id
role_id (int): 角色id
Returns:
_type_: _description_
"""
stmt = (
select(ExplanationStyleRobotPairing.pairing_id, ExplanationStyleRobotPairing.explanation_style_id, ExplanationStyle.name, ExplanationStyle.detail, ExplanationStyleRobotPairing.status, ExplanationStyleRobotPairing.robot_role_id)
.select_from(ExplanationStyleRobotPairing)
.join(ExplanationStyle, ExplanationStyle.explanation_style_id == ExplanationStyleRobotPairing.explanation_style_id)
.where(ExplanationStyleRobotPairing.robot_id == robot_id, ExplanationStyleRobotPairing.robot_role_id == role_id)
)
result = (await db.execute(stmt)).mappings().all()
return result
@classmethod
async def switch_explanation_style(cls, db: AsyncSession, robot_id: int = None, pairing_id: int = None, robot_role_id: str = None ,status:str = '0', update_by: str = None):
condition = list()
if robot_id:
condition.append(ExplanationStyleRobotPairing.robot_id == robot_id)
if pairing_id:
condition.append(ExplanationStyleRobotPairing.pairing_id == pairing_id)
if robot_role_id:
condition.append(ExplanationStyleRobotPairing.robot_role_id == robot_role_id)
query = (
update(ExplanationStyleRobotPairing)
.values(status=status)
.where(*condition)
)
return await db.execute(query)
@classmethod
async def get_style_robot_pair_list(cls, db: AsyncSession, robot_id: int):
query = (
select(ExplanationStyleRobotPairing.pairing_id, ExplanationStyle.name, ExplanationStyle.detail, ExplanationStyleRobotPairing.status)
.select_from(ExplanationStyleRobotPairing)
.join(ExplanationStyle, ExplanationStyle.explanation_style_id == ExplanationStyleRobotPairing.explanation_style_id)
.where(ExplanationStyleRobotPairing.robot_id == robot_id)
)
result = (await db.execute(query)).mappings().all()
return result
@classmethod
async def get_explanation_style_robot_pair_detail_by_id(cls, db: AsyncSession, pairing_id: int):
"""
根据主键ID获取讲解风格--机器人配对详细信息
:param db: orm对象
:param pairing_id: 主键ID
:return: 讲解风格--机器人配对信息对象
"""
explanation_style_robot_pair_info = (
(
await db.execute(
select(ExplanationStyleRobotPairing)
.where(
ExplanationStyleRobotPairing.pairing_id == pairing_id
)
)
)
.scalars()
.first()
)
return explanation_style_robot_pair_info
@classmethod
async def get_explanation_style_robot_pair_detail_by_info(cls, db: AsyncSession, explanation_style_robot_pair: Explanation_style_robot_pairModel):
"""
根据讲解风格--机器人配对参数获取讲解风格--机器人配对信息
:param db: orm对象
:param explanation_style_robot_pair: 讲解风格--机器人配对参数对象
:return: 讲解风格--机器人配对信息对象
"""
explanation_style_robot_pair_info = (
(
await db.execute(
select(ExplanationStyleRobotPairing).where(
)
)
)
.scalars()
.first()
)
return explanation_style_robot_pair_info
@classmethod
async def get_explanation_style_robot_pair_list(cls, db: AsyncSession, query_object: Explanation_style_robot_pairPageQueryModel, is_page: bool = False):
"""
根据查询参数获取讲解风格--机器人配对列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 讲解风格--机器人配对列表信息对象
"""
query = (
select(ExplanationStyleRobotPairing)
.where(
ExplanationStyleRobotPairing.robot_id == query_object.robot_id if query_object.robot_id else True,
ExplanationStyleRobotPairing.explanation_style_id == query_object.explanation_style_id if query_object.explanation_style_id else True,
ExplanationStyleRobotPairing.prompt == query_object.prompt if query_object.prompt else True,
ExplanationStyleRobotPairing.status == query_object.status if query_object.status else True,
ExplanationStyleRobotPairing.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_create_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_create_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_create_time and query_object.end_create_time
else True,
ExplanationStyleRobotPairing.update_time.between(
datetime.combine(datetime.strptime(query_object.begin_update_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_update_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_update_time and query_object.end_update_time
else True,
)
.order_by(ExplanationStyleRobotPairing.pairing_id)
.distinct()
)
explanation_style_robot_pair_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return explanation_style_robot_pair_list
@classmethod
async def add_explanation_style_robot_pair_dao(cls, db: AsyncSession, explanation_style_robot_pair: Explanation_style_robot_pairModel):
"""
新增讲解风格--机器人配对数据库操作
:param db: orm对象
:param explanation_style_robot_pair: 讲解风格--机器人配对对象
:return:
"""
db_explanation_style_robot_pair = ExplanationStyleRobotPairing(**explanation_style_robot_pair.model_dump(exclude={}))
db.add(db_explanation_style_robot_pair)
await db.flush()
return db_explanation_style_robot_pair
@classmethod
async def edit_explanation_style_robot_pair_dao(cls, db: AsyncSession, explanation_style_robot_pair: dict):
"""
编辑讲解风格--机器人配对数据库操作
:param db: orm对象
:param explanation_style_robot_pair: 需要更新的讲解风格--机器人配对字典
:return:
"""
await db.execute(update(ExplanationStyleRobotPairing), [explanation_style_robot_pair])
@classmethod
async def delete_explanation_style_robot_pair_dao(cls, db: AsyncSession, explanation_style_robot_pair: Explanation_style_robot_pairModel):
"""
删除讲解风格--机器人配对数据库操作
:param db: orm对象
:param explanation_style_robot_pair: 讲解风格--机器人配对对象
:return:
"""
await db.execute(delete(ExplanationStyleRobotPairing).where(ExplanationStyleRobotPairing.pairing_id.in_([explanation_style_robot_pair.pairing_id])))

View File

@ -1,129 +0,0 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.identification_record_do import IdentificationRecord
from module_admin.entity.vo.identification_record_vo import Identification_recordModel, Identification_recordPageQueryModel
from utils.page_util import PageUtil
class Identification_recordDao:
"""
识别记录模块数据库操作层
"""
@classmethod
async def get_identification_record_detail_by_id(cls, db: AsyncSession, id: int):
"""
根据主键 自增获取识别记录详细信息
:param db: orm对象
:param id: 主键 自增
:return: 识别记录信息对象
"""
identification_record_info = (
(
await db.execute(
select(IdentificationRecord)
.where(
IdentificationRecord.id == id
)
)
)
.scalars()
.first()
)
return identification_record_info
@classmethod
async def get_identification_record_detail_by_info(cls, db: AsyncSession, identification_record: Identification_recordModel):
"""
根据识别记录参数获取识别记录信息
:param db: orm对象
:param identification_record: 识别记录参数对象
:return: 识别记录信息对象
"""
identification_record_info = (
(
await db.execute(
select(IdentificationRecord).where(
)
)
)
.scalars()
.first()
)
return identification_record_info
@classmethod
async def get_identification_record_list(cls, db: AsyncSession, query_object: Identification_recordPageQueryModel, is_page: bool = False):
"""
根据查询参数获取识别记录列表信息
:param db: orm对象
:param query_object: 查询参数对象
:param is_page: 是否开启分页
:return: 识别记录列表信息对象
"""
query = (
select(IdentificationRecord)
.where(
IdentificationRecord.person_name.like(f'%{query_object.person_name}%') if query_object.person_name else True,
IdentificationRecord.door_name.like(f'%{query_object.door_name}%') if query_object.door_name else True,
IdentificationRecord.status == query_object.status if query_object.status else True,
IdentificationRecord.source == query_object.source if query_object.source else True,
IdentificationRecord.create_time.between(
datetime.combine(datetime.strptime(query_object.begin_create_time, '%Y-%m-%d'), time(00, 00, 00)),
datetime.combine(datetime.strptime(query_object.end_create_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_create_time and query_object.end_create_time
else True,
)
.order_by(IdentificationRecord.create_time.desc())
.distinct()
)
identification_record_list = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
return identification_record_list
@classmethod
async def add_identification_record_dao(cls, db: AsyncSession, identification_record: Identification_recordModel):
"""
新增识别记录数据库操作
:param db: orm对象
:param identification_record: 识别记录对象
:return:
"""
# 排除 id 字段(自增主键),但保留其他所有字段
data = identification_record.model_dump(exclude={'id'}, exclude_none=True)
db_identification_record = IdentificationRecord(**data)
db.add(db_identification_record)
await db.flush()
return db_identification_record
@classmethod
async def edit_identification_record_dao(cls, db: AsyncSession, identification_record: dict):
"""
编辑识别记录数据库操作
:param db: orm对象
:param identification_record: 需要更新的识别记录字典
:return:
"""
await db.execute(update(IdentificationRecord), [identification_record])
@classmethod
async def delete_identification_record_dao(cls, db: AsyncSession, identification_record: Identification_recordModel):
"""
删除识别记录数据库操作
:param db: orm对象
:param identification_record: 识别记录对象
:return:
"""
await db.execute(delete(IdentificationRecord).where(IdentificationRecord.id.in_([identification_record.id])))

Some files were not shown because too many files have changed in this diff Show More