mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 04:46:26 +00:00
feat: 优化代码生成器功能并修复多个问题
- 前端表格列添加溢出提示工具 - 后端登录IP归属地查询与设置统一处理 - 分页服务明确仅用于非SQL数据源场景 - 代码生成器添加字段筛选和帮助面板 - 修复菜单高亮和布局切换问题 - 更新文档中的BUG状态和解决方案 - 优化AI聊天界面样式和交互 - 添加数据库分页支持到多个模块 - 代码生成器表单校验和流程优化 - 修复PostgreSQL日期类型问题
This commit is contained in:
@@ -145,14 +145,7 @@ class LoginService:
|
||||
# 若没有 X-Forwarded-For 头,则使用 request.client.host
|
||||
request_ip = request.client.host if request.client else "127.0.0.1"
|
||||
|
||||
if settings.LOGIN_RESOLVE_IP_LOCATION:
|
||||
login_location = await IpLocalUtil.get_ip_location(request_ip)
|
||||
else:
|
||||
login_location = (
|
||||
"内网IP"
|
||||
if IpLocalUtil.is_private_ip(request_ip)
|
||||
else "未解析(已关闭归属地查询)"
|
||||
)
|
||||
login_location = await IpLocalUtil.resolve_location_for_log(request_ip)
|
||||
request.scope["login_location"] = login_location
|
||||
|
||||
# 确保在请求上下文中设置用户名和会话ID
|
||||
|
||||
@@ -5,7 +5,6 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
||||
from redis.asyncio.client import Redis
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.base_schema import BatchSetAvailable
|
||||
@@ -82,13 +81,12 @@ async def get_type_list_controller(
|
||||
异常:
|
||||
- CustomException: 查询字典类型失败时抛出异常。
|
||||
"""
|
||||
result_dict_list = await DictTypeService.get_obj_list_service(
|
||||
auth=auth, search=search, order_by=page.order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await DictTypeService.get_obj_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=page.order_by,
|
||||
)
|
||||
log.info("查询字典类型列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询字典类型列表成功")
|
||||
@@ -331,13 +329,12 @@ async def get_data_list_controller(
|
||||
order_by = [{"order": "asc"}]
|
||||
if page.order_by:
|
||||
order_by = page.order_by
|
||||
result_dict_list = await DictDataService.get_obj_list_service(
|
||||
auth=auth, search=search, order_by=order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await DictDataService.get_obj_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=order_by,
|
||||
)
|
||||
log.info("查询字典数据列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询字典数据列表成功")
|
||||
|
||||
@@ -67,6 +67,25 @@ class DictTypeService:
|
||||
)
|
||||
return [DictTypeOutSchema.model_validate(obj).model_dump() for obj in obj_list]
|
||||
|
||||
@classmethod
|
||||
async def get_obj_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: DictTypeQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询字典类型(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await DictTypeCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=DictTypeOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_obj_service(
|
||||
cls, auth: AuthSchema, redis: Redis, data: DictTypeCreateSchema
|
||||
@@ -308,6 +327,25 @@ class DictDataService:
|
||||
)
|
||||
return [DictDataOutSchema.model_validate(obj).model_dump() for obj in obj_list]
|
||||
|
||||
@classmethod
|
||||
async def get_obj_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: DictDataQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询字典数据(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await DictDataCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=DictDataOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def init_dict_service(cls, redis: Redis) -> None:
|
||||
"""
|
||||
|
||||
@@ -4,7 +4,6 @@ from fastapi import APIRouter, Body, Depends, Path
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.dependencies import AuthPermission
|
||||
@@ -43,13 +42,12 @@ async def get_obj_list_controller(
|
||||
order_by = [{"created_time": "desc"}]
|
||||
if page.order_by:
|
||||
order_by = page.order_by
|
||||
result_dict_list = await OperationLogService.get_log_list_service(
|
||||
search=search, auth=auth, order_by=order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await OperationLogService.get_log_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=order_by,
|
||||
)
|
||||
log.info("查询日志成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询日志成功")
|
||||
|
||||
@@ -56,6 +56,25 @@ class OperationLogService:
|
||||
log_dict_list = [OperationLogOutSchema.model_validate(log).model_dump() for log in log_list]
|
||||
return log_dict_list
|
||||
|
||||
@classmethod
|
||||
async def get_log_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: OperationLogQueryParam | None = None,
|
||||
order_by: list | None = None,
|
||||
) -> dict:
|
||||
"""分页查询操作日志(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await OperationLogCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=OperationLogOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_log_service(cls, auth: AuthSchema, data: OperationLogCreateSchema) -> dict:
|
||||
"""
|
||||
|
||||
@@ -4,7 +4,6 @@ from fastapi import APIRouter, Body, Depends, Path
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.base_schema import BatchSetAvailable
|
||||
@@ -66,13 +65,12 @@ async def get_obj_list_controller(
|
||||
返回:
|
||||
- JSONResponse: 包含分页公告详情的响应模型。
|
||||
"""
|
||||
result_dict_list = await NoticeService.get_notice_list_service(
|
||||
auth=auth, search=search, order_by=page.order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await NoticeService.get_notice_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=page.order_by,
|
||||
)
|
||||
log.info("查询公告列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询公告列表成功")
|
||||
@@ -229,7 +227,6 @@ async def get_obj_list_available_controller(
|
||||
返回:
|
||||
- JSONResponse: 包含分页已启用公告详情的响应模型。
|
||||
"""
|
||||
result_dict_list = await NoticeService.get_notice_list_available_service(auth=auth)
|
||||
result_dict = await PaginationService.paginate(data_list=result_dict_list)
|
||||
result_dict = await NoticeService.get_notice_available_page_service(auth=auth)
|
||||
log.info("查询已启用公告列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询已启用公告列表成功")
|
||||
|
||||
@@ -75,6 +75,36 @@ class NoticeService:
|
||||
for notice_obj in notice_obj_list
|
||||
]
|
||||
|
||||
@classmethod
|
||||
async def get_notice_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: NoticeQueryParam | None = None,
|
||||
order_by: list[dict] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询公告(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await NoticeCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=NoticeOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def get_notice_available_page_service(cls, auth: AuthSchema) -> dict:
|
||||
"""已启用公告分页(与历史行为一致:默认第 1 页、每页 10 条)。"""
|
||||
return await NoticeCRUD(auth).page(
|
||||
offset=0,
|
||||
limit=10,
|
||||
order_by=[{"id": "asc"}],
|
||||
search={"status": "0"},
|
||||
out_schema=NoticeOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_notice_service(cls, auth: AuthSchema, data: NoticeCreateSchema) -> dict:
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,6 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
||||
from redis.asyncio.client import Redis
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.dependencies import AuthPermission, redis_getter
|
||||
@@ -118,13 +117,12 @@ async def get_obj_list_controller(
|
||||
返回:
|
||||
- JSONResponse: 包含参数列表的 JSON 响应
|
||||
"""
|
||||
result_dict_list = await ParamsService.get_obj_list_service(
|
||||
auth=auth, search=search, order_by=page.order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await ParamsService.get_obj_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=page.order_by,
|
||||
)
|
||||
log.info("获取参数列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询参数列表成功")
|
||||
|
||||
@@ -103,6 +103,25 @@ class ParamsService:
|
||||
obj_list = await ParamsCRUD(auth).get_obj_list_crud()
|
||||
return [ParamsOutSchema.model_validate(obj).model_dump() for obj in obj_list]
|
||||
|
||||
@classmethod
|
||||
async def get_obj_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: ParamsQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询参数(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await ParamsCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=ParamsOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_obj_service(
|
||||
cls, auth: AuthSchema, redis: Redis, data: ParamsCreateSchema
|
||||
|
||||
@@ -4,7 +4,6 @@ from fastapi import APIRouter, Body, Depends, Path
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.base_schema import BatchSetAvailable
|
||||
@@ -49,13 +48,12 @@ async def get_obj_list_controller(
|
||||
order_by = [{"order": "asc"}]
|
||||
if page.order_by:
|
||||
order_by = page.order_by
|
||||
result_dict_list = await PositionService.get_position_list_service(
|
||||
search=search, auth=auth, order_by=order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await PositionService.get_position_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=order_by,
|
||||
)
|
||||
log.info("查询岗位列表成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询岗位列表成功")
|
||||
|
||||
@@ -55,6 +55,25 @@ class PositionService:
|
||||
PositionOutSchema.model_validate(position).model_dump() for position in position_list
|
||||
]
|
||||
|
||||
@classmethod
|
||||
async def get_position_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: PositionQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询岗位(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await PositionCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=PositionOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_position_service(cls, auth: AuthSchema, data: PositionCreateSchema) -> dict:
|
||||
"""
|
||||
|
||||
@@ -4,7 +4,6 @@ from fastapi import APIRouter, Body, Depends, Path
|
||||
from fastapi.responses import JSONResponse, StreamingResponse
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.base_schema import BatchSetAvailable
|
||||
@@ -50,13 +49,12 @@ async def get_obj_list_controller(
|
||||
order_by = [{"order": "asc"}]
|
||||
if page.order_by:
|
||||
order_by = page.order_by
|
||||
result_dict_list = await RoleService.get_role_list_service(
|
||||
search=search, auth=auth, order_by=order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await RoleService.get_role_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=order_by,
|
||||
)
|
||||
log.info("查询角色成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询角色成功")
|
||||
|
||||
@@ -54,6 +54,25 @@ class RoleService:
|
||||
role_list = await RoleCRUD(auth).get_list_crud(search=search.__dict__, order_by=order_by)
|
||||
return [RoleOutSchema.model_validate(role).model_dump() for role in role_list]
|
||||
|
||||
@classmethod
|
||||
async def get_role_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: RoleQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询角色(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await RoleCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=RoleOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_role_service(cls, auth: AuthSchema, data: RoleCreateSchema) -> dict:
|
||||
"""
|
||||
|
||||
@@ -6,7 +6,6 @@ from fastapi.responses import JSONResponse, StreamingResponse
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.common.request import PaginationService
|
||||
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
|
||||
from app.core.base_params import PaginationQueryParam
|
||||
from app.core.base_schema import BatchSetAvailable
|
||||
@@ -225,13 +224,12 @@ async def get_obj_list_controller(
|
||||
返回:
|
||||
- JSONResponse: 分页查询结果JSON响应
|
||||
"""
|
||||
result_dict_list = await UserService.get_user_list_service(
|
||||
search=search, auth=auth, order_by=page.order_by
|
||||
)
|
||||
result_dict = await PaginationService.paginate(
|
||||
data_list=result_dict_list,
|
||||
result_dict = await UserService.get_user_page_service(
|
||||
auth=auth,
|
||||
page_no=page.page_no,
|
||||
page_size=page.page_size,
|
||||
search=search,
|
||||
order_by=page.order_by,
|
||||
)
|
||||
log.info("查询用户成功")
|
||||
return SuccessResponse(data=result_dict, msg="查询用户成功")
|
||||
|
||||
@@ -86,6 +86,25 @@ class UserService:
|
||||
|
||||
return user_dict_list
|
||||
|
||||
@classmethod
|
||||
async def get_user_page_service(
|
||||
cls,
|
||||
auth: AuthSchema,
|
||||
page_no: int,
|
||||
page_size: int,
|
||||
search: UserQueryParam | None = None,
|
||||
order_by: list[dict[str, str]] | None = None,
|
||||
) -> dict:
|
||||
"""分页查询用户(数据库 OFFSET/LIMIT)。"""
|
||||
offset = (page_no - 1) * page_size
|
||||
return await UserCRUD(auth).page(
|
||||
offset=offset,
|
||||
limit=page_size,
|
||||
order_by=order_by or [{"id": "asc"}],
|
||||
search=search.__dict__ if search else {},
|
||||
out_schema=UserOutSchema,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
async def create_user_service(cls, data: UserCreateSchema, auth: AuthSchema) -> dict:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user