feat: 添加编码管理
This commit is contained in:
parent
e32bb8e740
commit
6122e390fb
521
api/code.py
Normal file
521
api/code.py
Normal file
@ -0,0 +1,521 @@
|
||||
# _*_ coding : UTF-8 _*_
|
||||
# @Time : 2025/02/13 19:20
|
||||
# @UpdateTime : 2025/02/13 19:20
|
||||
# @Author : sonder
|
||||
# @File : code.py
|
||||
# @Software : PyCharm
|
||||
# @Comment : 本程序
|
||||
import os
|
||||
import time
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
import pandas as pd
|
||||
from elasticsearch.helpers import async_bulk
|
||||
from fastapi import APIRouter, Depends, Path, Request, Query
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
from fastapi.responses import JSONResponse, FileResponse
|
||||
|
||||
from annotation.log import Log
|
||||
from config.constant import BusinessType
|
||||
from config.env import ElasticSearchConfig
|
||||
from controller.login import LoginController
|
||||
from exceptions.exception import ServiceException, PermissionException
|
||||
from models import File, Code, QueryCode, QueryCodeLog
|
||||
from schemas.code import GetCodeInfoResponse, GetCodeListResponse, GetQueryCodeParams, \
|
||||
DeleteCodeListParams, QueryCodeResponse, AddCodeParams, GetQueryCodeLogResponse, GetQueryCodeLogDetailResponse
|
||||
from schemas.common import BaseResponse
|
||||
from utils.log import logger
|
||||
from utils.response import Response
|
||||
|
||||
codeAPI = APIRouter(
|
||||
prefix="/code",
|
||||
dependencies=[Depends(LoginController.get_current_user)]
|
||||
)
|
||||
|
||||
|
||||
@codeAPI.get("/template", summary="获取上传编码模板")
|
||||
@Log(title="获取上传编码模板", business_type=BusinessType.SELECT)
|
||||
async def get_upload_template(request: Request):
|
||||
template_path = os.path.join(os.path.abspath(os.getcwd()), 'assets', 'templates', '上传模版.xlsx')
|
||||
if not os.path.exists(template_path):
|
||||
raise ServiceException(message="文件不存在!")
|
||||
return FileResponse(
|
||||
path=template_path,
|
||||
filename="上传模版.xlsx",
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
)
|
||||
|
||||
|
||||
@codeAPI.get("/queryTemplate", summary="获取查询编码模板")
|
||||
@Log(title="获取查询编码模板", business_type=BusinessType.SELECT)
|
||||
async def get_query_template(request: Request):
|
||||
template_path = os.path.join(os.path.abspath(os.getcwd()), 'assets', 'templates', '查询模版.xlsx')
|
||||
if not os.path.exists(template_path):
|
||||
raise ServiceException(message="文件不存在!")
|
||||
return FileResponse(
|
||||
path=template_path,
|
||||
filename="查询模版.xlsx",
|
||||
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
||||
)
|
||||
|
||||
|
||||
@codeAPI.post("/add", response_class=JSONResponse, response_model=BaseResponse, summary="添加编码")
|
||||
@Log(title="添加编码", business_type=BusinessType.INSERT)
|
||||
async def add_code(request: Request, params: AddCodeParams):
|
||||
params.code = params.code.replace(".", "").replace("/", "").replace("_", "").replace("-", "").replace("?",
|
||||
"").replace(
|
||||
":", "").replace(":", "").replace("?", "").strip()
|
||||
if await Code.get_or_none(code=params.code):
|
||||
return Response.failure(msg="编码已存在")
|
||||
else:
|
||||
if await request.app.state.es.indices.exists(index=ElasticSearchConfig.ES_INDEX):
|
||||
await request.app.state.es.indices.create(index=ElasticSearchConfig.ES_INDEX, ignore=400)
|
||||
code = await Code.create(
|
||||
code=params.code,
|
||||
description=params.description
|
||||
)
|
||||
if code:
|
||||
# 构造 Bulk 导入数据
|
||||
actions = [
|
||||
{
|
||||
"_index": ElasticSearchConfig.ES_INDEX,
|
||||
"_id": code.code, # 以 code 作为 ID
|
||||
"_source": {
|
||||
"code": code.code,
|
||||
"description": code.description
|
||||
}
|
||||
}
|
||||
]
|
||||
success, failed = await async_bulk(request.app.state.es, actions)
|
||||
logger.info(f"成功导入 {success} 条数据,失败 {failed} 条")
|
||||
return Response.success(msg="添加成功")
|
||||
else:
|
||||
return Response.failure(msg="添加失败")
|
||||
|
||||
|
||||
@codeAPI.get("/addCode/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="导入编码")
|
||||
@Log(title="导入编码", business_type=BusinessType.INSERT)
|
||||
async def add_code_by_file(request: Request, id: str = Path(description="文件ID"),
|
||||
current_user=Depends(LoginController.get_current_user)):
|
||||
user_id = current_user.get("id")
|
||||
if file := await File.get_or_none(id=id):
|
||||
uploader_id = await file.first().values(id="uploader__id")
|
||||
if str(uploader_id["id"]) == user_id:
|
||||
try:
|
||||
df = pd.read_excel(file.absolute_path)
|
||||
for index, row in df.iterrows():
|
||||
row["code"] = str(row["code"]).replace(".", "").replace("/", "").replace("_", "").replace("-",
|
||||
"").replace(
|
||||
"?",
|
||||
"").replace(
|
||||
":", "").replace(":", "").replace("?", "").strip()
|
||||
await Code.create(
|
||||
code=row["code"],
|
||||
description=row["description"]
|
||||
)
|
||||
if not await request.app.state.es.indices.exists(index=ElasticSearchConfig.ES_INDEX):
|
||||
await request.app.state.es.indices.create(index=ElasticSearchConfig.ES_INDEX, ignore=400)
|
||||
# 构造 Bulk 导入数据
|
||||
actions = [
|
||||
{
|
||||
"_index": ElasticSearchConfig.ES_INDEX,
|
||||
"_id": row["code"], # 以 code 作为 ID
|
||||
"_source": {
|
||||
"code": row["code"],
|
||||
"description": row["description"]
|
||||
}
|
||||
}
|
||||
for _, row in df.iterrows()
|
||||
]
|
||||
success, failed = await async_bulk(request.app.state.es, actions)
|
||||
logger.info(f"成功导入 {success} 条数据,失败 {failed} 条")
|
||||
except ServiceException as e:
|
||||
logger.error(e.message)
|
||||
raise ServiceException(message="文件读取失败")
|
||||
return Response.success(msg="添加成功")
|
||||
else:
|
||||
raise PermissionException(message="权限不足")
|
||||
else:
|
||||
return Response.failure(msg="文件不存在")
|
||||
|
||||
|
||||
@codeAPI.delete("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码")
|
||||
@codeAPI.post("/delete/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="删除编码")
|
||||
@Log(title="删除编码", business_type=BusinessType.DELETE)
|
||||
async def delete_code_by_id(request: Request, id: str = Path(description="编码ID"), ):
|
||||
if code := await Code.get_or_none(id=id):
|
||||
await code.delete()
|
||||
await request.app.state.es.delete(index=ElasticSearchConfig.ES_INDEX, id=code.code)
|
||||
return Response.success(msg="删除成功")
|
||||
else:
|
||||
return Response.failure(msg="编码不存在")
|
||||
|
||||
|
||||
@codeAPI.delete("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码")
|
||||
@codeAPI.post("/deleteList", response_class=JSONResponse, response_model=BaseResponse, summary="批量删除编码")
|
||||
@Log(title="批量删除编码", business_type=BusinessType.DELETE)
|
||||
async def delete_code_by_ids(request: Request, params: DeleteCodeListParams):
|
||||
for id in set(params.ids):
|
||||
if code := await Code.get_or_none(id=id):
|
||||
await code.delete()
|
||||
await request.app.state.es.delete(index=ElasticSearchConfig.ES_INDEX, id=code.code)
|
||||
return Response.success(msg="删除成功")
|
||||
|
||||
|
||||
@codeAPI.put("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新编码")
|
||||
@codeAPI.post("/update/{id}", response_class=JSONResponse, response_model=BaseResponse, summary="更新编码")
|
||||
@Log(title="更新编码", business_type=BusinessType.UPDATE)
|
||||
async def update_code(request: Request,
|
||||
params: AddCodeParams,
|
||||
id: str = Path(description="编码ID")):
|
||||
if code := await Code.get_or_none(id=id):
|
||||
code.code = params.code
|
||||
code.description = params.description
|
||||
await code.save()
|
||||
await request.app.state.es.update(index=ElasticSearchConfig.ES_INDEX, id=code.code,
|
||||
body={"doc": {"description": params.description}})
|
||||
return Response.success(msg="更新成功")
|
||||
return Response.failure(msg="编码不存在")
|
||||
|
||||
|
||||
@codeAPI.get("/info/{id}", response_class=JSONResponse, response_model=GetCodeInfoResponse, summary="获取编码信息")
|
||||
@Log(title="获取编码信息", business_type=BusinessType.SELECT)
|
||||
async def get_code_info(request: Request, id: str = Path(description="编码ID")):
|
||||
if code := await Code.get_or_none(id=id).values(
|
||||
id="id",
|
||||
code="code",
|
||||
description="description",
|
||||
create_time="create_time",
|
||||
create_by="create_by",
|
||||
update_time="update_time",
|
||||
update_by="update_by"
|
||||
):
|
||||
return Response.success(data=code)
|
||||
return Response.failure(msg="编码不存在")
|
||||
|
||||
|
||||
@codeAPI.get("/list", response_class=JSONResponse, response_model=GetCodeListResponse, summary="获取编码列表")
|
||||
@Log(title="获取编码列表", business_type=BusinessType.SELECT)
|
||||
async def get_code_list(request: Request,
|
||||
page: int = Query(default=1, description="页码"),
|
||||
pageSize: int = Query(default=10, description="每页数量"),
|
||||
code: Optional[str] = Query(default=None, description="编码"),
|
||||
description: Optional[str] = Query(default=None, description="商品描述")):
|
||||
filterArgs = {
|
||||
f'{k}__contains': v for k, v in {
|
||||
'code': code,
|
||||
'description': description
|
||||
}.items() if v
|
||||
}
|
||||
total = await Code.filter(**filterArgs).count()
|
||||
data = await Code.filter(**filterArgs).offset((page - 1) * pageSize).limit(pageSize).values(
|
||||
id="id",
|
||||
code="code",
|
||||
description="description",
|
||||
create_time="create_time",
|
||||
create_by="create_by",
|
||||
update_time="update_time",
|
||||
update_by="update_by"
|
||||
)
|
||||
return Response.success(data={
|
||||
"page": page,
|
||||
"pageSize": pageSize,
|
||||
"total": total,
|
||||
"result": data
|
||||
})
|
||||
|
||||
|
||||
@codeAPI.post("/query", response_class=JSONResponse, response_model=QueryCodeResponse, summary="查询编码")
|
||||
@Log(title="查询编码", business_type=BusinessType.SELECT)
|
||||
async def get_code_list(request: Request,
|
||||
params: GetQueryCodeParams,
|
||||
current_user: dict = Depends(LoginController.get_current_user),
|
||||
):
|
||||
start_time = time.time()
|
||||
user_id = current_user.get("id")
|
||||
if log := await QueryCodeLog.create(
|
||||
operator_id=user_id,
|
||||
query_count=0,
|
||||
result_count=0,
|
||||
cost_time=0,
|
||||
request_params=params.query_text,
|
||||
response_result={},
|
||||
status=0,
|
||||
del_flag=0
|
||||
):
|
||||
description_list = set(params.query_text.split("\n"))
|
||||
query_count = 0
|
||||
dataList = []
|
||||
try:
|
||||
for description in description_list:
|
||||
if not description:
|
||||
continue
|
||||
query_count += 1
|
||||
query = {
|
||||
"query": {
|
||||
"match": {
|
||||
"brief_description": {
|
||||
"query": description.strip(),
|
||||
"fuzziness": "AUTO" # 自动模糊匹配
|
||||
}
|
||||
}
|
||||
},
|
||||
"sort": [
|
||||
{
|
||||
"_score": { # 按照匹配度排序
|
||||
"order": "desc" # 降序
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
matches = []
|
||||
data = await request.app.state.es.search(index=ElasticSearchConfig.ES_INDEX, body=query, size=5)
|
||||
# 获取当前查询的最大 _score
|
||||
max_score = data["hits"].get("max_score", 1)
|
||||
# 处理每一条匹配结果
|
||||
for hit in data["hits"]["hits"]:
|
||||
code = await Code.get_or_none(code=hit["_source"]["hts8"])
|
||||
# 归一化匹配度,转换为百分比
|
||||
match_rate = round((hit["_score"] / max_score) * 100, 2) # 归一化后计算百分比
|
||||
# 将匹配结果添加到列表中
|
||||
matches.append({
|
||||
"id": code.id if code else None,
|
||||
"code": hit["_source"]["hts8"], # 获取商品编码
|
||||
"description": hit["_source"]["brief_description"], # 获取商品描述
|
||||
"match_rate": match_rate # 匹配度(百分比)
|
||||
})
|
||||
query_code = await QueryCode.create(
|
||||
query_text=description.strip(),
|
||||
result_text=jsonable_encoder(matches),
|
||||
session_id=log.id
|
||||
)
|
||||
dataList.append({
|
||||
"id": query_code.id,
|
||||
"query_text": description.strip(),
|
||||
"result_text": jsonable_encoder(matches),
|
||||
"status": 1 if matches else 0,
|
||||
})
|
||||
|
||||
cost_time = float(time.time() - start_time) * 100
|
||||
log.operator_id = user_id
|
||||
log.query_count = query_count
|
||||
log.result_count = len(dataList)
|
||||
log.cost_time = cost_time
|
||||
log.status = 1 if dataList else 0
|
||||
log.response_result = jsonable_encoder(dataList)
|
||||
log.del_flag = 1
|
||||
await log.save()
|
||||
return Response.success(data={
|
||||
"id": log.id,
|
||||
"result_count": len(dataList),
|
||||
"query": params.query_text,
|
||||
"response_result": jsonable_encoder(dataList),
|
||||
"query_count": query_count,
|
||||
"cost_time": cost_time,
|
||||
"status": 1 if dataList else 0,
|
||||
"operation_time": log.operation_time
|
||||
})
|
||||
except ServiceException as e:
|
||||
logger.error(e.message)
|
||||
await log.delete()
|
||||
raise ServiceException(message="查询失败!")
|
||||
return Response.failure(msg="查询失败!")
|
||||
|
||||
|
||||
@codeAPI.get("/query/{id}", response_class=JSONResponse, response_model=QueryCodeResponse, summary="查询编码")
|
||||
@Log(title="查询编码", business_type=BusinessType.SELECT)
|
||||
async def get_code_list(request: Request,
|
||||
id: str = Path(description="文件ID"),
|
||||
current_user: dict = Depends(LoginController.get_current_user),
|
||||
):
|
||||
start_time = time.time()
|
||||
user_id = current_user.get("id")
|
||||
if file := await File.get_or_none(id=id):
|
||||
uploader_id = await file.first().values(id="uploader__id")
|
||||
if str(uploader_id["id"]) == user_id:
|
||||
if log := await QueryCodeLog.create(
|
||||
operator_id=user_id,
|
||||
query_count=0,
|
||||
result_count=0,
|
||||
cost_time=0,
|
||||
request_params="",
|
||||
response_result={},
|
||||
status=0,
|
||||
del_flag=0
|
||||
):
|
||||
try:
|
||||
query_text = ""
|
||||
query_count = 0
|
||||
dataList = []
|
||||
df = pd.read_excel(file.absolute_path)
|
||||
for index, row in df.iterrows():
|
||||
query_count += 1
|
||||
query_text += row["text"] + "\n"
|
||||
query = {
|
||||
"query": {
|
||||
"match": {
|
||||
"brief_description": {
|
||||
"query": row["text"].strip(),
|
||||
"fuzziness": "AUTO" # 自动模糊匹配
|
||||
}
|
||||
}
|
||||
},
|
||||
"sort": [
|
||||
{
|
||||
"_score": { # 按照匹配度排序
|
||||
"order": "desc" # 降序
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
matches = []
|
||||
data = await request.app.state.es.search(index=ElasticSearchConfig.ES_INDEX, body=query, size=5)
|
||||
# 获取当前查询的最大 _score
|
||||
max_score = data["hits"].get("max_score", 1)
|
||||
# 处理每一条匹配结果
|
||||
for hit in data["hits"]["hits"]:
|
||||
code = await Code.get_or_none(code=hit["_source"]["hts8"])
|
||||
# 归一化匹配度,转换为百分比
|
||||
match_rate = round((hit["_score"] / max_score) * 100, 2) # 归一化后计算百分比
|
||||
# 将匹配结果添加到列表中
|
||||
matches.append({
|
||||
"id": code.id if code else None,
|
||||
"code": hit["_source"]["hts8"], # 获取商品编码
|
||||
"description": hit["_source"]["brief_description"], # 获取商品描述
|
||||
"match_rate": match_rate # 匹配度(百分比)
|
||||
})
|
||||
query_code = await QueryCode.create(
|
||||
query_text=row['text'].strip(),
|
||||
result_text=jsonable_encoder(matches),
|
||||
session_id=log.id
|
||||
)
|
||||
dataList.append({
|
||||
"id": query_code.id,
|
||||
"query_text": row['text'].strip(),
|
||||
"result_text": jsonable_encoder(matches),
|
||||
"status": 1 if matches else 0,
|
||||
})
|
||||
|
||||
cost_time = float(time.time() - start_time) * 100
|
||||
log.request_params = query_text
|
||||
log.operator_id = user_id
|
||||
log.query_count = query_count
|
||||
log.result_count = len(dataList)
|
||||
log.cost_time = cost_time
|
||||
log.status = 1 if dataList else 0
|
||||
log.response_result = jsonable_encoder(dataList)
|
||||
log.del_flag = 1
|
||||
await log.save()
|
||||
return Response.success(data={
|
||||
"id": log.id,
|
||||
"result_count": len(dataList),
|
||||
"query": query_text,
|
||||
"response_result": jsonable_encoder(dataList),
|
||||
"query_count": query_count,
|
||||
"cost_time": cost_time,
|
||||
"status": 1 if dataList else 0,
|
||||
"operation_time": log.operation_time
|
||||
})
|
||||
except ServiceException as e:
|
||||
logger.error(e.message)
|
||||
await log.delete()
|
||||
raise ServiceException(message="查询失败!")
|
||||
else:
|
||||
raise PermissionException(message="权限不足")
|
||||
else:
|
||||
return Response.failure(msg="文件不存在")
|
||||
|
||||
|
||||
@codeAPI.get("/logList", response_class=JSONResponse, response_model=GetQueryCodeLogResponse,
|
||||
summary="查询编码日志列表")
|
||||
@Log(title="查询编码日志列表", business_type=BusinessType.SELECT)
|
||||
async def get_code_log_list(request: Request,
|
||||
page: int = Query(default=1, description="当前页码"),
|
||||
pageSize: int = Query(default=10, description="每页数量"),
|
||||
startTime: Optional[str] = Query(default=None, description="开始时间"),
|
||||
endTime: Optional[str] = Query(default=None, description="结束时间"),
|
||||
current_user: dict = Depends(LoginController.get_current_user),
|
||||
):
|
||||
user_id = current_user.get("id")
|
||||
if startTime and endTime:
|
||||
startTime = float(startTime) / 1000
|
||||
endTime = float(endTime) / 1000
|
||||
startTime = datetime.fromtimestamp(startTime)
|
||||
endTime = datetime.fromtimestamp(endTime)
|
||||
count = await QueryCodeLog.filter(operator_id=user_id, del_flag=1, operation_time__gte=startTime,
|
||||
operation_time__lte=endTime).count()
|
||||
data = await QueryCodeLog.filter(operator_id=user_id, del_flag=1, operation_time__gte=startTime,
|
||||
operation_time__lte=endTime).order_by("-operation_time").offset(
|
||||
(page - 1) * pageSize).limit(pageSize).values(
|
||||
id="id",
|
||||
query_count="query_count",
|
||||
result_count="result_count",
|
||||
cost_time="cost_time",
|
||||
operation_time="operation_time",
|
||||
status="status",
|
||||
request_params="request_params",
|
||||
response_result="response_result",
|
||||
create_time="create_time",
|
||||
update_time="update_time",
|
||||
operator_id="operator__id",
|
||||
operator_name="operator__username",
|
||||
operator_nickname="operator__nickname",
|
||||
department_id="operator__department__id",
|
||||
department_name="operator__department__name",
|
||||
)
|
||||
else:
|
||||
count = await QueryCodeLog.filter(operator_id=user_id, del_flag=1).count()
|
||||
data = await QueryCodeLog.filter(operator_id=user_id, del_flag=1).order_by("-operation_time").offset(
|
||||
(page - 1) * pageSize).limit(pageSize).values(
|
||||
id="id",
|
||||
query_count="query_count",
|
||||
result_count="result_count",
|
||||
cost_time="cost_time",
|
||||
operation_time="operation_time",
|
||||
status="status",
|
||||
request_params="request_params",
|
||||
response_result="response_result",
|
||||
create_time="create_time",
|
||||
update_time="update_time",
|
||||
operator_id="operator__id",
|
||||
operator_name="operator__username",
|
||||
operator_nickname="operator__nickname",
|
||||
department_id="operator__department__id",
|
||||
department_name="operator__department__name",
|
||||
)
|
||||
|
||||
return Response.success(data={
|
||||
"page": page,
|
||||
"pageSize": pageSize,
|
||||
"result": data,
|
||||
"total": count
|
||||
})
|
||||
|
||||
|
||||
@codeAPI.get("/logInfo/{id}", response_class=JSONResponse, response_model=GetQueryCodeLogDetailResponse,
|
||||
summary="查询编码日志详情")
|
||||
@Log(title="查询编码日志详情", business_type=BusinessType.SELECT)
|
||||
async def get_code_log_detail(request: Request,
|
||||
id: str = Path(..., description="日志ID"),
|
||||
):
|
||||
if log := await QueryCodeLog.get_or_none(id=id):
|
||||
data = await log.first().values(
|
||||
id="id",
|
||||
query_count="query_count",
|
||||
result_count="result_count",
|
||||
cost_time="cost_time",
|
||||
operation_time="operation_time",
|
||||
status="status",
|
||||
request_params="request_params",
|
||||
response_result="response_result",
|
||||
create_time="create_time",
|
||||
update_time="update_time",
|
||||
operator_id="operator__id",
|
||||
operator_name="operator__username",
|
||||
operator_nickname="operator__nickname",
|
||||
department_id="operator__department__id",
|
||||
department_name="operator__department__name",
|
||||
)
|
||||
return Response.success(data=data)
|
||||
return Response.failure(msg="日志不存在!")
|
@ -59,7 +59,7 @@ async def upload_file(
|
||||
file_type=file.content_type,
|
||||
absolute_path=absolute_path,
|
||||
relative_path=relative_path,
|
||||
uploader=current_user.get("id"),
|
||||
uploader_id=current_user.get("id"),
|
||||
)
|
||||
result = await file_record.first().values(
|
||||
id="id",
|
||||
|
2
app.py
2
app.py
@ -23,6 +23,7 @@ from api.permission import permissionAPI
|
||||
from api.role import roleAPI
|
||||
from api.server import serverAPI
|
||||
from api.user import userAPI
|
||||
from api.code import codeAPI
|
||||
from config.database import init_db, close_db
|
||||
from config.env import AppConfig
|
||||
from config.get_ElasticSearch import ElasticSearch
|
||||
@ -91,6 +92,7 @@ api_list = [
|
||||
{'api': serverAPI, 'tags': ['服务器管理']},
|
||||
{'api': i18nAPI, 'tags': ['国际化管理']},
|
||||
{'api': configApi, 'tags': ['配置管理']},
|
||||
{'api': codeAPI, 'tags': ['编码管理']},
|
||||
]
|
||||
|
||||
for api in api_list:
|
||||
|
@ -188,15 +188,27 @@ class LoginController:
|
||||
child_node = await cls.find_node_recursive(child_item["id"], data)
|
||||
if child_node:
|
||||
children.append(child_node)
|
||||
result = {
|
||||
"name": item["name"],
|
||||
"path": item["path"],
|
||||
"meta": {
|
||||
meta = {
|
||||
k: v for k, v in {
|
||||
"title": item["title"],
|
||||
"rank": item["rank"],
|
||||
"icon": item["icon"],
|
||||
"extraIcon": item["extraIcon"],
|
||||
"showParent": item["showParent"],
|
||||
"keepAlive": item["keepAlive"],
|
||||
"frameSrc": item["frameSrc"],
|
||||
"frameLoading": item["frameLoading"],
|
||||
"permissions": [item["auths"]],
|
||||
},
|
||||
}.items() if v
|
||||
}
|
||||
if item["showLink"]:
|
||||
meta["showLink"] = True
|
||||
else:
|
||||
meta["showLink"] = False
|
||||
result = {
|
||||
"name": item["name"],
|
||||
"path": item["path"],
|
||||
"meta": meta,
|
||||
"children": children
|
||||
}
|
||||
if item["component"]:
|
||||
|
@ -123,6 +123,9 @@ class QueryController:
|
||||
leaveTransition="permission__leave_transition",
|
||||
activePath="permission__active_path",
|
||||
auths="permission__auths",
|
||||
frameSrc="permission__frame_src",
|
||||
frameLoading="permission__frame_loading",
|
||||
fixedTag="permission__fixed_tag",
|
||||
keepAlive="permission__keep_alive",
|
||||
hiddenTag="permission__hidden_tag",
|
||||
showLink="permission__show_link",
|
||||
|
@ -6,6 +6,7 @@
|
||||
# @Software : PyCharm
|
||||
# @Comment : 本程序
|
||||
|
||||
from models.code import Code, QueryCode, QueryCodeLog
|
||||
from models.config import Config
|
||||
from models.department import Department, DepartmentRole
|
||||
from models.file import File
|
||||
@ -28,5 +29,8 @@ __all__ = [
|
||||
'UserRole',
|
||||
'I18n',
|
||||
'Locale',
|
||||
'Config'
|
||||
'Config',
|
||||
'Code',
|
||||
'QueryCode',
|
||||
'QueryCodeLog'
|
||||
]
|
||||
|
157
models/code.py
Normal file
157
models/code.py
Normal file
@ -0,0 +1,157 @@
|
||||
# _*_ coding : UTF-8 _*_
|
||||
# @Time : 2025/02/13 21:23
|
||||
# @UpdateTime : 2025/02/13 21:23
|
||||
# @Author : sonder
|
||||
# @File : code.py
|
||||
# @Software : PyCharm
|
||||
# @Comment : 本程序
|
||||
from tortoise import fields
|
||||
|
||||
from models.common import BaseModel
|
||||
|
||||
|
||||
class Code(BaseModel):
|
||||
"""
|
||||
编码模型
|
||||
"""
|
||||
code = fields.CharField(
|
||||
max_length=255,
|
||||
description="编码",
|
||||
source_field="code"
|
||||
)
|
||||
|
||||
description = fields.TextField(
|
||||
description="描述",
|
||||
source_field="description"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
table = "code"
|
||||
table_description = "编码表"
|
||||
|
||||
|
||||
class QueryCodeLog(BaseModel):
|
||||
"""
|
||||
查询编码日志模型
|
||||
"""
|
||||
request_params = fields.TextField(
|
||||
null=True,
|
||||
description="请求参数",
|
||||
source_field="request_params" # 映射到数据库字段 request_params
|
||||
)
|
||||
"""
|
||||
请求参数。
|
||||
- 记录用户请求的参数(任意格式,如字符串、JSON、XML 等)。
|
||||
- 允许为空。
|
||||
- 映射到数据库字段 request_params。
|
||||
"""
|
||||
|
||||
response_result = fields.TextField(
|
||||
null=True,
|
||||
description="返回结果",
|
||||
source_field="response_result" # 映射到数据库字段 response_result
|
||||
)
|
||||
"""
|
||||
返回结果。
|
||||
- 记录操作的返回结果(任意格式,如字符串、JSON、XML 等)。
|
||||
- 允许为空。
|
||||
- 映射到数据库字段 response_result。
|
||||
"""
|
||||
|
||||
status = fields.SmallIntField(
|
||||
default=1,
|
||||
description="操作状态(1成功,0失败)",
|
||||
source_field="status" # 映射到数据库字段 status
|
||||
)
|
||||
"""
|
||||
操作状态。
|
||||
- 1:成功
|
||||
- 0:失败
|
||||
- 默认为 1。
|
||||
- 映射到数据库字段 status。
|
||||
"""
|
||||
|
||||
operation_time = fields.DatetimeField(
|
||||
auto_now_add=True,
|
||||
description="操作时间",
|
||||
source_field="operation_time" # 映射到数据库字段 operation_time
|
||||
)
|
||||
"""
|
||||
操作时间。
|
||||
- 自动设置为当前时间。
|
||||
- 映射到数据库字段 operation_time。
|
||||
"""
|
||||
|
||||
cost_time = fields.FloatField(
|
||||
default=0,
|
||||
description="消耗时间(毫秒)",
|
||||
source_field="cost_time" # 映射到数据库字段 cost_time
|
||||
)
|
||||
"""
|
||||
消耗时间。
|
||||
- 记录操作消耗的时间(单位:毫秒)。
|
||||
- 默认为 0。
|
||||
- 映射到数据库字段 cost_time。
|
||||
"""
|
||||
query_count = fields.IntField(
|
||||
default=0,
|
||||
description="查询统计",
|
||||
source_field="query_count" # 映射到数据库字段 query_count
|
||||
)
|
||||
"""
|
||||
查询统计。
|
||||
- 记录查询文本的数量。
|
||||
- 默认为 0。
|
||||
- 映射到数据库字段 query_count。
|
||||
"""
|
||||
result_count = fields.IntField(
|
||||
default=0,
|
||||
description="结果统计",
|
||||
source_field="result_count" # 映射到数据库字段 result_count
|
||||
)
|
||||
"""
|
||||
结果统计。
|
||||
- 记录查询结果的数量。
|
||||
- 默认为 0。
|
||||
- 映射到数据库字段 result_count。
|
||||
"""
|
||||
operator = fields.ForeignKeyField(
|
||||
"models.User",
|
||||
related_name="query_code_logs",
|
||||
description="操作人员",
|
||||
source_field="operator_id" # 映射到数据库字段 operator_id
|
||||
)
|
||||
"""
|
||||
操作人员。
|
||||
- 外键关联到 User 表。
|
||||
- 允许为空。
|
||||
- 映射到数据库字段 operator_id。
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
table = "query_code_log"
|
||||
table_description = "查询编码日志表"
|
||||
|
||||
|
||||
class QueryCode(BaseModel):
|
||||
"""
|
||||
查询编码模型
|
||||
"""
|
||||
session = fields.ForeignKeyField(
|
||||
"models.QueryCodeLog",
|
||||
related_name="query_code",
|
||||
description="会话ID",
|
||||
source_field="session_id"
|
||||
)
|
||||
query_text = fields.TextField(
|
||||
description="查询文本",
|
||||
source_field="query_text" # 映射到数据库字段 query_text
|
||||
)
|
||||
result_text = fields.TextField(
|
||||
description="结果文本",
|
||||
source_field="result_text" # 映射到数据库字段 result_text
|
||||
)
|
||||
|
||||
class Meta:
|
||||
table = "query_code"
|
||||
table_description = "查询编码表"
|
BIN
requirements.txt
BIN
requirements.txt
Binary file not shown.
174
schemas/code.py
Normal file
174
schemas/code.py
Normal file
@ -0,0 +1,174 @@
|
||||
# _*_ coding : UTF-8 _*_
|
||||
# @Time : 2025/02/13 22:07
|
||||
# @UpdateTime : 2025/02/13 22:07
|
||||
# @Author : sonder
|
||||
# @File : code.py
|
||||
# @Software : PyCharm
|
||||
# @Comment : 本程序
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic.alias_generators import to_camel
|
||||
|
||||
from schemas.common import BaseResponse, ListQueryResult
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class CodeInfo(BaseModel):
|
||||
"""
|
||||
编码信息模型
|
||||
"""
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
id: str = Field(..., description="主键")
|
||||
create_by: str = Field(default="", description="创建者")
|
||||
create_time: Optional[datetime] = Field(default=None, description="创建时间")
|
||||
update_by: str = Field(default="", description="更新者")
|
||||
update_time: Optional[datetime] = Field(default=None, description="更新时间")
|
||||
code: str = Field(..., description="编码")
|
||||
description: str = Field(..., description="描述")
|
||||
|
||||
|
||||
class AddCodeParams(BaseModel):
|
||||
"""
|
||||
更新编码参数
|
||||
"""
|
||||
code: str = Field(..., description="编码")
|
||||
description: str = Field(..., description="描述")
|
||||
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
|
||||
|
||||
class DeleteCodeListParams(BaseModel):
|
||||
"""
|
||||
删除编码参数
|
||||
"""
|
||||
ids: List[str] = Field(..., description="删除ID列表")
|
||||
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
|
||||
|
||||
class GetCodeInfoResponse(BaseResponse):
|
||||
"""
|
||||
获取编码信息响应
|
||||
"""
|
||||
data: CodeInfo = Field(..., description="编码信息")
|
||||
|
||||
|
||||
class GetCodeListResult(ListQueryResult):
|
||||
"""
|
||||
获取编码列表结果
|
||||
"""
|
||||
result: List[CodeInfo] = Field(..., description="编码列表")
|
||||
|
||||
|
||||
class GetCodeListResponse(BaseResponse):
|
||||
"""
|
||||
获取编码列表响应
|
||||
"""
|
||||
data: GetCodeListResult = Field(..., description="编码列表")
|
||||
|
||||
|
||||
class GetQueryCodeParams(BaseModel):
|
||||
"""
|
||||
获取查询编码结果
|
||||
"""
|
||||
query_text: str = Field(..., description="查询文本")
|
||||
|
||||
|
||||
class QueryResultItem(BaseModel):
|
||||
"""
|
||||
查询结果项
|
||||
"""
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
id: str = Field(..., description="主键")
|
||||
code: str = Field(..., description="编码")
|
||||
description: str = Field(..., description="描述")
|
||||
match_rate: float = Field(..., description="匹配度")
|
||||
|
||||
|
||||
class QueryResult(BaseModel):
|
||||
"""
|
||||
查询结果
|
||||
"""
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
id: str = Field(..., description="主键")
|
||||
query_text: str = Field(..., description="查询文本")
|
||||
status: int = Field(..., description="查询状态")
|
||||
result: List[QueryResultItem] = Field(..., description="查询结果")
|
||||
|
||||
|
||||
class QueryCodeResult(BaseModel):
|
||||
"""
|
||||
查询编码结果
|
||||
"""
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
id: str = Field(..., description="查询ID")
|
||||
query: str = Field(..., description="查询文本")
|
||||
query_count: int = Field(..., description="查询统计")
|
||||
cost_time: float = Field(..., description="消耗时间(毫秒)")
|
||||
result_count: int = Field(..., description="结果统计")
|
||||
response_result: List[QueryResult] = Field(..., description="查询结果")
|
||||
status: int = Field(..., description="查询状态")
|
||||
operator_time: str = Field(default="", description="操作时间")
|
||||
|
||||
|
||||
class QueryCodeResponse(BaseResponse):
|
||||
"""
|
||||
查询编码响应
|
||||
"""
|
||||
data: QueryCodeResult = Field(..., description="查询编码结果")
|
||||
|
||||
|
||||
class QueryCodeLogInfo(BaseModel):
|
||||
"""
|
||||
查询编码日志信息
|
||||
"""
|
||||
model_config = ConfigDict(
|
||||
alias_generator=to_camel
|
||||
)
|
||||
id: str = Field(default="", description="主键")
|
||||
query_count: int = Field(default=0, description="查询统计")
|
||||
result_count: int = Field(default=0, description="结果统计")
|
||||
cost_time: float = Field(default=0.0, description="消耗时间(毫秒)")
|
||||
operator_time: str = Field(default="", description="操作时间")
|
||||
request_params: str = Field(default="", description="请求参数")
|
||||
response_result: str = Field(default="", description="响应结果")
|
||||
status: int = Field(default=0, description="查询状态")
|
||||
operator_id: str = Field(default="", description="操作人员ID")
|
||||
operator_name: str = Field(default="", description="操作人员名称")
|
||||
operator_nickname: str = Field(default="", description="操作人员昵称")
|
||||
department_id: str = Field(default="", description="操作人员部门ID")
|
||||
department_name: str = Field(default="", description="操作人员部门名称")
|
||||
|
||||
|
||||
class QueryCodeLogResult(ListQueryResult):
|
||||
"""
|
||||
查询编码日志结果
|
||||
"""
|
||||
result: List[QueryCodeLogInfo] = Field(..., description="查询编码日志列表")
|
||||
|
||||
|
||||
class GetQueryCodeLogResponse(BaseResponse):
|
||||
"""
|
||||
查询编码日志响应
|
||||
"""
|
||||
data: QueryCodeLogResult = Field(..., description="查询编码日志结果")
|
||||
|
||||
|
||||
class GetQueryCodeLogDetailResponse(BaseResponse):
|
||||
"""
|
||||
查询编码日志详情响应
|
||||
"""
|
||||
data: QueryCodeLogInfo = Field(..., description="查询编码日志详情")
|
@ -28,6 +28,7 @@ class ListQueryResult(BaseModel):
|
||||
result: List = Field(default=[], description="列表数据")
|
||||
total: int = Field(default=0, description="总条数")
|
||||
page: int = Field(default=1, description="当前页码")
|
||||
pageSize: int = Field(default=10, description="每页数量")
|
||||
|
||||
|
||||
class DeleteListParams(BaseModel):
|
||||
|
Loading…
x
Reference in New Issue
Block a user