refactor: 完成项目整体架构升级与依赖优化

此提交包含多项核心优化:
1.  依赖库升级:更新FastAPI、替换fastapi-limiter为slowapi,更换MySQL驱动为aiomysql,重构缓存系统使用fastapi-cache2-fork
2.  代码重构:移除自定义缓存工具,统一使用fastapi-cache2;重构请求限流逻辑,修复操作日志记录开关逻辑
3.  接口规范:统一将Depends分页/查询参数改为Query注解,补全File上传依赖注解
4.  前端优化:调整登录滑块进度条颜色、移除冗余demo页面样式类
5.  日志优化:重构日志配置,使用time.perf_counter替代time.time统计耗时
6.  测试优化:移除冗余的限流mock配置,改用官方限流方案
7.  模板优化:更新vue代码生成模板,移除冗余导入并优化组件使用
8.  导入功能优化:移除pandas依赖,使用Excel工具类重构文件导入逻辑
This commit is contained in:
zhangtao
2026-07-01 00:35:28 +08:00
parent a39bedabb9
commit a86233d6c2
51 changed files with 1126 additions and 42754 deletions
@@ -2,22 +2,22 @@ import json
import secrets
from typing import Annotated
from fastapi import APIRouter, BackgroundTasks, Depends, Path, Query, Request
from fastapi import APIRouter, BackgroundTasks, Depends, Path, Query, Body, Form, Request
from fastapi.responses import JSONResponse, RedirectResponse
from redis.asyncio.client import Redis
from sqlalchemy.ext.asyncio import AsyncSession
from app.common.response import ErrorResponse, ResponseSchema, SuccessResponse
from app.config.setting import settings
from app.core import cache_util
from app.core.base_schema import (
AuthSchema,
JWTOutSchema,
LogoutPayloadSchema,
RefreshTokenPayloadSchema,
)
from app.core.cache_util import cache
from app.core.dependencies import db_getter, get_current_user, redis_getter
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from app.core.exceptions import CustomException
from app.core.logger import logger
from app.core.redis_crud import RedisCURD
@@ -65,8 +65,8 @@ async def login_for_access_token_controller(
request: Request,
background_tasks: BackgroundTasks,
redis: Annotated[Redis, Depends(redis_getter)],
login_form: Annotated[CustomOAuth2PasswordRequestForm, Depends()],
db: Annotated[AsyncSession, Depends(db_getter)],
login_form: Annotated[CustomOAuth2PasswordRequestForm, Form(description="登录表单")],
) -> JSONResponse | dict:
login_result = await LoginService.authenticate_user(
request=request, redis=redis, login_form=login_form, db=db, background_tasks=background_tasks
@@ -85,9 +85,9 @@ async def login_for_access_token_controller(
response_model=ResponseSchema[JWTOutSchema],
)
async def get_new_token_controller(
payload: RefreshTokenPayloadSchema,
db: Annotated[AsyncSession, Depends(db_getter)],
redis: Annotated[Redis, Depends(redis_getter)],
payload: Annotated[RefreshTokenPayloadSchema, Body(description="刷新token参数")],
) -> JSONResponse:
new_token = await LoginService.refresh_token(db=db, redis=redis, refresh_token=payload)
return SuccessResponse(data=new_token, msg="刷新成功")
@@ -112,8 +112,8 @@ async def get_captcha_for_login_controller(
response_model=ResponseSchema[None],
)
async def logout_controller(
payload: LogoutPayloadSchema,
redis: Annotated[Redis, Depends(redis_getter)],
payload: Annotated[LogoutPayloadSchema, Body(description="退出登录参数")],
) -> JSONResponse:
if await LoginService.logout(redis=redis, token=payload):
logger.info("退出成功")
@@ -144,7 +144,7 @@ async def get_auto_login_token_controller(
auth: Annotated[AuthSchema, Depends(get_current_user)],
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
user_id: int,
user_id: Annotated[int, Body(description="用户ID")],
) -> JSONResponse:
tenant_id = None if auth.user.is_superuser else auth.user.tenant_id
result = await AutoLoginService.create_auto_login_token(redis=redis, db=db, user_id=user_id, tenant_id=tenant_id)
@@ -160,7 +160,7 @@ async def auto_login_controller(
request: Request,
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
token: str,
token: Annotated[str, Body(description="免登录Token")],
) -> JSONResponse:
login_token = await AutoLoginService.auto_login(request=request, redis=redis, db=db, token=token)
logger.info("用户免登录成功")
@@ -175,12 +175,12 @@ async def auto_login_controller(
)
async def select_tenant_controller(
request: Request,
data: SelectTenantSchema,
auth: Annotated[AuthSchema, Depends(get_current_user)],
redis: Annotated[Redis, Depends(redis_getter)],
data: Annotated[SelectTenantSchema, Body(description="租户选择参数")],
) -> JSONResponse:
result = await LoginService(auth).select_tenant(request=request, redis=redis, tenant_id=data.tenant_id)
await cache_util.clear(namespace=_AUTH_TENANTS_NS)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="租户切换成功")
@@ -193,7 +193,6 @@ async def select_tenant_controller(
@cache(expire=120, namespace=_AUTH_TENANTS_NS)
async def get_user_tenants_controller(
auth: Annotated[AuthSchema, Depends(get_current_user)],
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
service = LoginService(auth)
tenants = await service.get_user_tenants()
@@ -208,10 +207,7 @@ async def oauth_login_redirect_controller(
request: Request,
redis: Annotated[Redis, Depends(redis_getter)],
provider: Annotated[str, Path(description="wechat | qq | github | gitee")],
redirect_uri: Annotated[
str | None,
Query(description="OAuth 完成后浏览器回到的前端登录页完整 URL"),
] = None,
redirect_uri: Annotated[str | None, Query(description="OAuth 完成后浏览器回到的前端登录页完整 URL")] = None,
) -> RedirectResponse:
allowed = {"wechat", "qq", "github", "gitee"}
fe = redirect_uri or settings.OAUTH_FRONTEND_FALLBACK
@@ -252,9 +248,9 @@ async def oauth_callback_controller(
request: Request,
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
provider: Annotated[str, Path()],
code: Annotated[str | None, Query()] = None,
state: Annotated[str | None, Query()] = None,
provider: Annotated[str, Path(description="wechat | qq | github | gitee")],
code: Annotated[str | None, Query(description="OAuth 授权码")] = None,
state: Annotated[str | None, Query(description="OAuth 状态参数")] = None,
) -> RedirectResponse:
fe_fallback = settings.OAUTH_FRONTEND_FALLBACK
@@ -300,8 +296,8 @@ async def oauth_callback_controller(
response_model=ResponseSchema[TenantRegisterOutSchema],
)
async def tenant_register_controller(
data: TenantRegisterSchema,
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[TenantRegisterSchema, Body(description="租户注册参数")],
) -> JSONResponse:
result = await TenantRegisterService.register(
db=db,
@@ -1,14 +1,14 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse
from app.common.response import ResponseSchema, SuccessResponse
from app.core import cache_util
from app.core.base_schema import AuthSchema, BatchSetAvailable
from app.core.cache_util import cache
from app.core.dependencies import AuthPermission
from app.core.router_class import OperationLogRoute
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from .schema import DeptCreateSchema, DeptOutSchema, DeptQueryParam, DeptUpdateSchema
from .service import DeptService
@@ -24,8 +24,8 @@ _DEPT_NS = "dept"
)
@cache(expire=300, namespace=_DEPT_NS)
async def get_dept_tree_controller(
search: Annotated[DeptQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:query"]))],
search: Annotated[DeptQueryParam, Query(description="部门查询参数")],
) -> JSONResponse:
order_by = [{"order": "asc"}]
result_dict_tree = await DeptService(auth).tree(search=search, order_by=order_by)
@@ -37,8 +37,8 @@ async def get_dept_tree_controller(
response_model=ResponseSchema[DeptOutSchema],
)
async def get_obj_detail_controller(
id: Annotated[int, Path(description="部门ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:detail"]))],
id: Annotated[int, Path(description="部门ID")],
) -> JSONResponse:
result_dict = await DeptService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="查询部门详情成功")
@@ -49,11 +49,11 @@ async def get_obj_detail_controller(
response_model=ResponseSchema[DeptOutSchema],
)
async def create_obj_controller(
data: DeptCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:create"]))],
data: Annotated[DeptCreateSchema, Body(description="部门创建参数")],
) -> JSONResponse:
result_dict = await DeptService(auth).create(data=data)
await cache_util.clear(namespace=_DEPT_NS)
await FastAPICache.clear(namespace=_DEPT_NS)
return SuccessResponse(data=result_dict, msg="创建部门成功")
@DeptRouter.put(
@@ -62,12 +62,12 @@ async def create_obj_controller(
response_model=ResponseSchema[DeptOutSchema],
)
async def update_obj_controller(
data: DeptUpdateSchema,
id: Annotated[int, Path(description="部门ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:update"]))],
id: Annotated[int, Path(description="部门ID")],
data: Annotated[DeptUpdateSchema, Body(description="部门修改参数")],
) -> JSONResponse:
result_dict = await DeptService(auth).update(id=id, data=data)
await cache_util.clear(namespace=_DEPT_NS)
await FastAPICache.clear(namespace=_DEPT_NS)
return SuccessResponse(data=result_dict, msg="修改部门成功")
@DeptRouter.delete(
@@ -76,11 +76,11 @@ async def update_obj_controller(
response_model=ResponseSchema[None],
)
async def delete_obj_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await DeptService(auth).delete(ids=ids)
await cache_util.clear(namespace=_DEPT_NS)
await FastAPICache.clear(namespace=_DEPT_NS)
return SuccessResponse(msg="删除部门成功")
@DeptRouter.patch(
@@ -89,9 +89,9 @@ async def delete_obj_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_obj_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dept:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改部门状态参数")],
) -> JSONResponse:
await DeptService(auth).batch_set_available(data=data)
await cache_util.clear(namespace=_DEPT_NS)
await FastAPICache.clear(namespace=_DEPT_NS)
return SuccessResponse(msg="批量修改部门状态成功")
@@ -1,15 +1,15 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from redis.asyncio.client import Redis
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core import cache_util
from app.core.base_params import PaginationQueryParam
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema
from app.core.cache_util import cache
from app.core.dependencies import AuthPermission, redis_getter
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from app.core.router_class import OperationLogRoute
from app.utils.common_util import bytes2file_response
@@ -35,8 +35,8 @@ _DICT_TYPE_NS = "dict_type"
response_model=ResponseSchema[DictTypeOutSchema],
)
async def get_type_detail_controller(
id: Annotated[int, Path(description="字典类型ID", ge=1)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:detail"]))],
id: Annotated[int, Path(description="字典类型ID", ge=1)],
) -> JSONResponse:
result_dict = await DictTypeService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取字典类型详情成功")
@@ -47,9 +47,9 @@ async def get_type_detail_controller(
response_model=ResponseSchema[PageResultSchema[DictTypeOutSchema]],
)
async def get_type_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[DictTypeQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页查询参数")],
search: Annotated[DictTypeQueryParam, Query(description="字典类型查询参数")],
) -> JSONResponse:
result_dict = await DictTypeService(auth).page(
page_no=page.page_no,
@@ -77,12 +77,12 @@ async def get_type_optionselect_controller(
response_model=ResponseSchema[DictTypeOutSchema],
)
async def create_type_controller(
data: DictTypeCreateSchema,
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:create"]))],
data: Annotated[DictTypeCreateSchema, Body(description="字典类型创建参数")],
) -> JSONResponse:
result_dict = await DictTypeService(auth).create(redis=redis, data=data)
await cache_util.clear(namespace=_DICT_TYPE_NS)
await FastAPICache.clear(namespace=_DICT_TYPE_NS)
return SuccessResponse(data=result_dict, msg="创建字典类型成功")
@DictRouter.put(
@@ -91,13 +91,13 @@ async def create_type_controller(
response_model=ResponseSchema[DictTypeOutSchema],
)
async def update_type_controller(
data: DictTypeUpdateSchema,
redis: Annotated[Redis, Depends(redis_getter)],
id: Annotated[int, Path(description="字典类型ID", ge=1)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:update"]))],
id: Annotated[int, Path(description="字典类型ID", ge=1)],
data: Annotated[DictTypeUpdateSchema, Body(description="字典类型修改参数")],
) -> JSONResponse:
result_dict = await DictTypeService(auth).update(redis=redis, id=id, data=data)
await cache_util.clear(namespace=_DICT_TYPE_NS)
await FastAPICache.clear(namespace=_DICT_TYPE_NS)
return SuccessResponse(data=result_dict, msg="修改字典类型成功")
@DictRouter.delete(
@@ -107,11 +107,11 @@ async def update_type_controller(
)
async def delete_type_controller(
redis: Annotated[Redis, Depends(redis_getter)],
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:delete"]))],
ids: Annotated[list[int], Body(description="字典类型ID列表")],
) -> JSONResponse:
await DictTypeService(auth).delete(redis=redis, ids=ids)
await cache_util.clear(namespace=_DICT_TYPE_NS)
await FastAPICache.clear(namespace=_DICT_TYPE_NS)
return SuccessResponse(msg="删除字典类型成功")
@DictRouter.patch(
@@ -120,11 +120,11 @@ async def delete_type_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_dict_type_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改字典类型状态参数")],
) -> JSONResponse:
await DictTypeService(auth).set_available(data=data)
await cache_util.clear(namespace=_DICT_TYPE_NS)
await FastAPICache.clear(namespace=_DICT_TYPE_NS)
return SuccessResponse(msg="批量修改字典类型状态成功")
@DictRouter.post(
@@ -133,8 +133,8 @@ async def batch_set_available_dict_type_controller(
response_model=ResponseSchema[None],
)
async def export_type_list_controller(
search: Annotated[DictTypeQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_type:export"]))],
search: Annotated[DictTypeQueryParam, Query(description="字典类型查询参数")],
) -> StreamingResponse:
# 获取全量数据并转为dict列表
result_dict_list = await DictTypeService(auth).get_list(search=search)
@@ -153,8 +153,8 @@ async def export_type_list_controller(
response_model=ResponseSchema[DictDataOutSchema],
)
async def get_data_detail_controller(
id: Annotated[int, Path(description="字典数据ID", ge=1)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:detail"]))],
id: Annotated[int, Path(description="字典数据ID", ge=1)],
) -> JSONResponse:
result_dict = await DictDataService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取字典数据详情成功")
@@ -165,9 +165,9 @@ async def get_data_detail_controller(
response_model=ResponseSchema[PageResultSchema[DictDataOutSchema]],
)
async def get_data_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[DictDataQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[DictDataQueryParam, Query(description="字典数据查询参数")],
) -> JSONResponse:
order_by = [{"order": "asc"}]
if page.order_by:
@@ -186,9 +186,9 @@ async def get_data_list_controller(
response_model=ResponseSchema[DictDataOutSchema],
)
async def create_data_controller(
data: DictDataCreateSchema,
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:create"]))],
data: Annotated[DictDataCreateSchema, Body(description="字典数据创建参数")],
) -> JSONResponse:
result_dict = await DictDataService(auth).create(redis=redis, data=data)
return SuccessResponse(data=result_dict, msg="创建字典数据成功")
@@ -199,10 +199,10 @@ async def create_data_controller(
response_model=ResponseSchema[DictDataOutSchema],
)
async def update_data_controller(
data: DictDataUpdateSchema,
redis: Annotated[Redis, Depends(redis_getter)],
id: Annotated[int, Path(description="字典数据ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:update"]))],
id: Annotated[int, Path(description="字典数据ID")],
data: Annotated[DictDataUpdateSchema, Body(description="字典数据修改参数")],
) -> JSONResponse:
result_dict = await DictDataService(auth).update(redis=redis, id=id, data=data)
return SuccessResponse(data=result_dict, msg="修改字典数据成功")
@@ -214,8 +214,8 @@ async def update_data_controller(
)
async def delete_data_controller(
redis: Annotated[Redis, Depends(redis_getter)],
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await DictDataService(auth).delete(redis=redis, ids=ids)
return SuccessResponse(msg="删除字典数据成功")
@@ -226,8 +226,8 @@ async def delete_data_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_dict_data_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改字典数据状态参数")],
) -> JSONResponse:
await DictDataService(auth).set_available(data=data)
return SuccessResponse(msg="批量修改字典数据状态成功")
@@ -238,9 +238,9 @@ async def batch_set_available_dict_data_controller(
response_model=ResponseSchema[None],
)
async def export_data_list_controller(
search: Annotated[DictDataQueryParam, Depends()],
page: Annotated[PaginationQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:dict_data:export"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[DictDataQueryParam, Query(description="字典数据查询参数")],
) -> StreamingResponse:
result_dict_list = await DictDataService(auth).get_list(search=search, order_by=page.order_by)
export_data = [item.model_dump() for item in result_dict_list]
@@ -257,7 +257,10 @@ async def export_data_list_controller(
summary="根据字典类型获取数据",
response_model=ResponseSchema[list[DictDataOutSchema]],
)
async def get_init_dict_data_controller(dict_type: str, redis: Annotated[Redis, Depends(redis_getter)]) -> JSONResponse:
async def get_init_dict_data_controller(
redis: Annotated[Redis, Depends(redis_getter)],
dict_type: Annotated[str, Path(description="字典类型")],
) -> JSONResponse:
dict_data_query_result = await DictDataService.get_init_cache(redis=redis, dict_type=dict_type, tenant_id=1)
return SuccessResponse(data=dict_data_query_result, msg="获取初始化字典数据成功")
@@ -1,6 +1,6 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse
from app.common.response import ResponseSchema, SuccessResponse
@@ -30,8 +30,8 @@ LogRouter = APIRouter(route_class=OperationLogRoute, prefix="/log", tags=["系
response_model=ResponseSchema[LoginLogDetailOutSchema],
)
async def get_log_detail_controller(
id: Annotated[int, Path(description="登录日志ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:login_log:query"]))],
id: Annotated[int, Path(description="登录日志ID")],
) -> JSONResponse:
result_dict = await LoginLogService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取登录日志详情成功")
@@ -43,9 +43,9 @@ async def get_log_detail_controller(
response_model=ResponseSchema[PageResultSchema[LoginLogOutSchema]],
)
async def get_log_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[LoginLogQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:login_log:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[LoginLogQueryParam, Query(description="登录日志查询参数")],
) -> JSONResponse:
result_dict = await LoginLogService(auth).page(
page_no=page.page_no,
@@ -62,8 +62,8 @@ async def get_log_list_controller(
response_model=ResponseSchema[LoginLogDetailOutSchema],
)
async def create_log_controller(
data: LoginLogCreateSchema,
auth: Annotated[AuthSchema, Depends(get_current_user)],
data: Annotated[LoginLogCreateSchema, Body(description="登录日志创建参数")],
) -> JSONResponse:
result_dict = await LoginLogService(auth).create(data=data)
return SuccessResponse(data=result_dict, msg="创建登录日志成功")
@@ -75,8 +75,8 @@ async def create_log_controller(
response_model=ResponseSchema,
)
async def delete_log_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:login_log:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await LoginLogService(auth).delete(ids=ids)
return SuccessResponse(msg="删除登录日志成功")
@@ -89,9 +89,8 @@ async def delete_log_controller(
dependencies=[Depends(AuthPermission(["module_system:log:query"]))],
)
async def get_operation_log_detail_controller(
*,
id: Annotated[int, Path(gt=0)],
auth: Annotated[AuthSchema, Depends(get_current_user)],
id: Annotated[int, Path(description="操作日志ID", gt=0)],
):
result_dict = await OperationLogService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取操作日志详情成功")
@@ -103,11 +102,10 @@ async def get_operation_log_detail_controller(
response_model=ResponseSchema[PageResultSchema[OperationLogOutSchema]],
dependencies=[Depends(AuthPermission(["module_system:log:query"]))],
)
async def list(
*,
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[OperationLogQueryParam, Depends()],
async def get_operation_log_list_controller(
auth: Annotated[AuthSchema, Depends(get_current_user)],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[OperationLogQueryParam, Query(description="操作日志查询参数")],
):
result_dict = await OperationLogService(auth).page(
page_no=page.page_no,
@@ -124,9 +122,8 @@ async def list(
response_model=ResponseSchema[OperationLogDetailOutSchema],
)
async def create_operation_log_controller(
*,
data: OperationLogCreateSchema,
auth: Annotated[AuthSchema, Depends(get_current_user)],
data: Annotated[OperationLogCreateSchema, Body(description="操作日志创建参数")],
):
result_dict = await OperationLogService(auth).create(data=data)
return SuccessResponse(data=result_dict, msg="创建操作日志成功")
@@ -139,9 +136,8 @@ async def create_operation_log_controller(
dependencies=[Depends(AuthPermission(["module_system:log:delete"]))],
)
async def delete(
*,
data: BatchDelete,
auth: Annotated[AuthSchema, Depends(get_current_user)],
data: Annotated[BatchDelete, Body(description="ID列表")],
):
await OperationLogService(auth).delete(ids=data.ids)
return SuccessResponse(msg="删除操作日志成功")
@@ -1,14 +1,14 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core import cache_util
from app.core.base_params import PaginationQueryParam
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema
from app.core.cache_util import cache
from app.core.dependencies import AuthPermission, get_current_user
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from app.core.logger import logger
from app.core.router_class import OperationLogRoute
from app.utils.common_util import bytes2file_response
@@ -32,8 +32,8 @@ _NOTICE_NS = "notice"
response_model=ResponseSchema[NoticeOutSchema],
)
async def get_notice_detail_controller(
id: Annotated[int, Path(description="公告ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:detail"]))],
id: Annotated[int, Path(description="公告ID")],
) -> JSONResponse:
result_dict = await NoticeService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取公告详情成功")
@@ -44,9 +44,9 @@ async def get_notice_detail_controller(
response_model=ResponseSchema[PageResultSchema[NoticeOutSchema]],
)
async def get_notice_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[NoticeQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[NoticeQueryParam, Query(description="公告查询参数")],
) -> JSONResponse:
result_dict = await NoticeService(auth).page(
page_no=page.page_no,
@@ -62,11 +62,11 @@ async def get_notice_list_controller(
response_model=ResponseSchema[NoticeOutSchema],
)
async def create_notice_controller(
data: NoticeCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:create"]))],
data: Annotated[NoticeCreateSchema, Body(description="公告创建参数")],
) -> JSONResponse:
result_dict = await NoticeService(auth).create(data=data)
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
return SuccessResponse(data=result_dict, msg="创建公告成功")
@NoticeRouter.put(
@@ -75,12 +75,12 @@ async def create_notice_controller(
response_model=ResponseSchema[NoticeOutSchema],
)
async def update_notice_controller(
data: NoticeUpdateSchema,
id: Annotated[int, Path(description="公告ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:update"]))],
id: Annotated[int, Path(description="公告ID")],
data: Annotated[NoticeUpdateSchema, Body(description="公告修改参数")],
) -> JSONResponse:
result_dict = await NoticeService(auth).update(id=id, data=data)
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
return SuccessResponse(data=result_dict, msg="修改公告成功")
@NoticeRouter.delete(
@@ -89,11 +89,11 @@ async def update_notice_controller(
response_model=ResponseSchema[None],
)
async def delete_notice_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await NoticeService(auth).delete(ids=ids)
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
return SuccessResponse(msg="删除公告成功")
@NoticeRouter.patch(
@@ -102,11 +102,11 @@ async def delete_notice_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_notice_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改公告状态参数")],
) -> JSONResponse:
await NoticeService(auth).set_available(data=data)
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
return SuccessResponse(msg="批量修改公告状态成功")
@NoticeRouter.post(
@@ -114,8 +114,8 @@ async def batch_set_available_notice_controller(
summary="导出公告",
)
async def export_notice_list_controller(
search: Annotated[NoticeQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:notice:export"]))],
search: Annotated[NoticeQueryParam, Query(description="公告查询参数")],
) -> StreamingResponse:
result_dict_list = await NoticeService(auth).get_list(search=search)
export_data = [item.model_dump() for item in result_dict_list]
@@ -158,12 +158,12 @@ async def get_notification_panel_controller(
response_model=ResponseSchema[None],
)
async def mark_read_controller(
id: Annotated[int, Path(description="通知ID")],
auth: Annotated[AuthSchema, Depends(get_current_user)],
id: Annotated[int, Path(description="通知ID")],
) -> JSONResponse:
"""标记已读。通过 `sys_notice_read` 表记录已读时间。"""
await NoticeService(auth).mark_read(notice_id=id)
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
logger.info(f"用户[{auth.user.id}]标记通知[{id}]已读")
return SuccessResponse(msg="标记已读成功")
@@ -177,7 +177,7 @@ async def mark_all_read_controller(
) -> JSONResponse:
"""全部标记已读。返回本次操作标记的数量。"""
count = await NoticeService(auth).mark_all_read()
await cache_util.clear(namespace=_NOTICE_NS)
await FastAPICache.clear(namespace=_NOTICE_NS)
logger.info(f"用户[{auth.user.id}]全部已读, 数量={count}")
return SuccessResponse(data=count, msg=f"全部标记已读成功,共标记 {count}")
@@ -1,6 +1,6 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from redis.asyncio.client import Redis
@@ -22,8 +22,8 @@ ParamsRouter = APIRouter(route_class=OperationLogRoute, prefix="/param", tags=["
response_model=ResponseSchema[ParamsOutSchema],
)
async def get_param_detail_controller(
id: Annotated[int, Path(description="参数ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:detail"]))],
id: Annotated[int, Path(description="参数ID")],
) -> JSONResponse:
result_dict = await ParamsService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取参数详情成功")
@@ -34,8 +34,8 @@ async def get_param_detail_controller(
response_model=ResponseSchema[ParamsOutSchema],
)
async def get_param_by_key_controller(
config_key: Annotated[str, Path(description="配置键")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:query"]))],
config_key: Annotated[str, Path(description="配置键")],
) -> JSONResponse:
result_dict = await ParamsService(auth).get_by_key(config_key=config_key)
return SuccessResponse(data=result_dict, msg="根据配置键获取参数详情成功")
@@ -46,8 +46,8 @@ async def get_param_by_key_controller(
response_model=ResponseSchema[ParamsOutSchema],
)
async def get_config_value_by_key_controller(
config_key: Annotated[str, Path(description="配置键")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:query"]))],
config_key: Annotated[str, Path(description="配置键")],
) -> JSONResponse:
result_value = await ParamsService(auth).get_config_value_by_key(config_key=config_key)
return SuccessResponse(data=result_value, msg="根据配置键获取参数值成功")
@@ -59,8 +59,8 @@ async def get_config_value_by_key_controller(
)
async def get_param_list_controller(
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:query"]))],
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[ParamsQueryParam, Depends()],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[ParamsQueryParam, Query(description="参数查询参数")],
) -> JSONResponse:
result_dict = await ParamsService(auth).page(
page_no=page.page_no,
@@ -76,9 +76,9 @@ async def get_param_list_controller(
response_model=ResponseSchema[ParamsOutSchema],
)
async def create_param_controller(
data: ParamsCreateSchema,
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:create"]))],
data: Annotated[ParamsCreateSchema, Body(description="参数创建参数")],
) -> JSONResponse:
result_dict = await ParamsService(auth).create(redis=redis, data=data)
return SuccessResponse(data=result_dict, msg="创建参数成功")
@@ -89,10 +89,10 @@ async def create_param_controller(
response_model=ResponseSchema[ParamsOutSchema],
)
async def update_param_controller(
data: ParamsUpdateSchema,
id: Annotated[int, Path(description="参数ID")],
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:update"]))],
id: Annotated[int, Path(description="参数ID")],
data: Annotated[ParamsUpdateSchema, Body(description="参数修改参数")],
) -> JSONResponse:
result_dict = await ParamsService(auth).update(redis=redis, id=id, data=data)
return SuccessResponse(data=result_dict, msg="更新参数成功")
@@ -104,8 +104,8 @@ async def update_param_controller(
)
async def delete_param_controller(
redis: Annotated[Redis, Depends(redis_getter)],
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await ParamsService(auth).delete(redis=redis, ids=ids)
return SuccessResponse(msg="删除参数成功")
@@ -116,9 +116,9 @@ async def delete_param_controller(
response_model=ResponseSchema,
)
async def batch_set_status_controller(
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:patch"]))],
ids: Annotated[list[int], Body(description="参数ID列表")],
status: Annotated[int, Body(description="状态值")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:patch"]))],
) -> JSONResponse:
await ParamsService(auth).batch_set_status(ids=ids, status=status)
return SuccessResponse(msg="批量设置参数状态成功")
@@ -129,8 +129,8 @@ async def batch_set_status_controller(
response_model=ResponseSchema[None],
)
async def export_param_list_controller(
search: Annotated[ParamsQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:param:export"]))],
search: Annotated[ParamsQueryParam, Query(description="参数查询参数")],
) -> StreamingResponse:
result_dict_list = await ParamsService(auth).get_list(search=search)
export_data = [item.model_dump() for item in result_dict_list]
@@ -1,15 +1,15 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core import cache_util
from app.core.base_params import PaginationQueryParam
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema
from app.core.cache_util import cache
from app.core.dependencies import AuthPermission
from app.core.router_class import OperationLogRoute
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from app.utils.common_util import bytes2file_response
from .schema import (
@@ -31,9 +31,9 @@ _POS_NS = "position"
)
@cache(expire=300, namespace=_POS_NS)
async def get_obj_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[PositionQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[PositionQueryParam, Query(description="岗位查询参数")],
) -> JSONResponse:
order_by = [{"order": "asc"}]
if page.order_by:
@@ -52,8 +52,8 @@ async def get_obj_list_controller(
response_model=ResponseSchema[PositionOutSchema],
)
async def get_obj_detail_controller(
id: Annotated[int, Path(description="岗位ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:detail"]))],
id: Annotated[int, Path(description="岗位ID")],
) -> JSONResponse:
result_dict = await PositionService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取岗位详情成功")
@@ -64,11 +64,11 @@ async def get_obj_detail_controller(
response_model=ResponseSchema[PositionOutSchema],
)
async def create_obj_controller(
data: PositionCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:create"]))],
data: Annotated[PositionCreateSchema, Body(description="岗位创建参数")],
) -> JSONResponse:
result_dict = await PositionService(auth).create(data=data)
await cache_util.clear(namespace=_POS_NS)
await FastAPICache.clear(namespace=_POS_NS)
return SuccessResponse(data=result_dict, msg="创建岗位成功")
@PositionRouter.put(
@@ -77,12 +77,12 @@ async def create_obj_controller(
response_model=ResponseSchema[PositionOutSchema],
)
async def update_obj_controller(
data: PositionUpdateSchema,
id: Annotated[int, Path(description="岗位ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:update"]))],
id: Annotated[int, Path(description="岗位ID")],
data: Annotated[PositionUpdateSchema, Body(description="岗位修改参数")],
) -> JSONResponse:
result_dict = await PositionService(auth).update(id=id, data=data)
await cache_util.clear(namespace=_POS_NS)
await FastAPICache.clear(namespace=_POS_NS)
return SuccessResponse(data=result_dict, msg="修改岗位成功")
@PositionRouter.delete(
@@ -91,11 +91,11 @@ async def update_obj_controller(
response_model=ResponseSchema[None],
)
async def delete_obj_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await PositionService(auth).delete(ids=ids)
await cache_util.clear(namespace=_POS_NS)
await FastAPICache.clear(namespace=_POS_NS)
return SuccessResponse(msg="删除岗位成功")
@PositionRouter.patch(
@@ -104,11 +104,11 @@ async def delete_obj_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_obj_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改岗位状态参数")],
) -> JSONResponse:
await PositionService(auth).set_available(data=data)
await cache_util.clear(namespace=_POS_NS)
await FastAPICache.clear(namespace=_POS_NS)
return SuccessResponse(msg="批量修改岗位状态成功")
@PositionRouter.get(
@@ -117,8 +117,8 @@ async def batch_set_available_obj_controller(
response_model=ResponseSchema[None],
)
async def export_obj_list_controller(
search: Annotated[PositionQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:position:export"]))],
search: Annotated[PositionQueryParam, Query(description="岗位查询参数")],
) -> StreamingResponse:
position_query_result = await PositionService(auth).get_list(search=search)
position_export_result = PositionService.export_list(position_list=position_query_result)
@@ -1,15 +1,15 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path
from fastapi import APIRouter, Body, Depends, Path, Query
from fastapi.responses import JSONResponse, StreamingResponse
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core import cache_util
from app.core.base_params import PaginationQueryParam
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema
from app.core.cache_util import cache
from app.core.dependencies import AuthPermission
from app.core.router_class import OperationLogRoute
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from app.utils.common_util import bytes2file_response
from .schema import (
@@ -32,9 +32,9 @@ _ROLE_NS = "role"
)
@cache(expire=300, namespace=_ROLE_NS)
async def get_role_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[RoleQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[RoleQueryParam, Query(description="角色查询参数")],
) -> JSONResponse:
order_by = [{"order": "asc"}]
if page.order_by:
@@ -53,8 +53,8 @@ async def get_role_list_controller(
response_model=ResponseSchema[RoleOutSchema],
)
async def get_role_detail_controller(
id: Annotated[int, Path(description="角色ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:detail"]))],
id: Annotated[int, Path(description="角色ID")],
) -> JSONResponse:
result_dict = await RoleService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取角色详情成功")
@@ -65,11 +65,11 @@ async def get_role_detail_controller(
response_model=ResponseSchema[RoleOutSchema],
)
async def create_role_controller(
data: RoleCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:create"]))],
data: Annotated[RoleCreateSchema, Body(description="角色创建参数")],
) -> JSONResponse:
result_dict = await RoleService(auth).create(data=data)
await cache_util.clear(namespace=_ROLE_NS)
await FastAPICache.clear(namespace=_ROLE_NS)
return SuccessResponse(data=result_dict, msg="创建角色成功")
@RoleRouter.put(
@@ -78,12 +78,12 @@ async def create_role_controller(
response_model=ResponseSchema[RoleOutSchema],
)
async def update_role_controller(
data: RoleUpdateSchema,
id: Annotated[int, Path(description="角色ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:update"]))],
id: Annotated[int, Path(description="角色ID")],
data: Annotated[RoleUpdateSchema, Body(description="角色修改参数")],
) -> JSONResponse:
result_dict = await RoleService(auth).update(id=id, data=data)
await cache_util.clear(namespace=_ROLE_NS)
await FastAPICache.clear(namespace=_ROLE_NS)
return SuccessResponse(data=result_dict, msg="修改角色成功")
@RoleRouter.delete(
@@ -92,11 +92,11 @@ async def update_role_controller(
response_model=ResponseSchema[None],
)
async def delete_role_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await RoleService(auth).delete(ids=ids)
await cache_util.clear(namespace=_ROLE_NS)
await FastAPICache.clear(namespace=_ROLE_NS)
return SuccessResponse(msg="删除角色成功")
@RoleRouter.patch(
@@ -105,11 +105,11 @@ async def delete_role_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_role_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改角色状态参数")],
) -> JSONResponse:
await RoleService(auth).set_available(data=data)
await cache_util.clear(namespace=_ROLE_NS)
await FastAPICache.clear(namespace=_ROLE_NS)
return SuccessResponse(msg="批量修改角色状态成功")
@RoleRouter.put(
@@ -118,11 +118,11 @@ async def batch_set_available_role_controller(
response_model=ResponseSchema[None],
)
async def set_role_permission_controller(
data: RolePermissionSettingSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:permission"]))],
data: Annotated[RolePermissionSettingSchema, Body(description="角色授权参数")],
) -> JSONResponse:
await RoleService(auth).set_permission(data=data)
await cache_util.clear(namespace=_ROLE_NS)
await FastAPICache.clear(namespace=_ROLE_NS)
return SuccessResponse(msg="授权角色成功")
@RoleRouter.get(
@@ -131,8 +131,8 @@ async def set_role_permission_controller(
response_model=ResponseSchema[None],
)
async def export_role_list_controller(
search: Annotated[RoleQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:role:export"]))],
search: Annotated[RoleQueryParam, Query(description="角色查询参数")],
) -> StreamingResponse:
role_query_result = await RoleService(auth).get_list(search=search)
role_export_result = RoleService.export_list(role_list=role_query_result)
@@ -1,6 +1,6 @@
from typing import Annotated
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, Query, Path, Body
from fastapi.responses import JSONResponse
from app.common.response import ResponseSchema, SuccessResponse
@@ -22,9 +22,9 @@ TicketRouter = APIRouter(route_class=OperationLogRoute, prefix="/ticket", tags=[
@TicketRouter.get("/list", summary="工单列表", response_model=ResponseSchema[PageResultSchema[TicketOutSchema]])
async def ticket_list_controller(
search: Annotated[TicketQueryParam, Depends()],
page: Annotated[PaginationQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:list"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[TicketQueryParam, Query(description="工单查询参数")],
) -> JSONResponse:
result = await TicketService(auth).page(
page_no=page.page_no,
@@ -36,41 +36,41 @@ async def ticket_list_controller(
@TicketRouter.get("/detail/{id}", summary="获取工单详情", response_model=ResponseSchema[TicketOutSchema])
async def ticket_detail_controller(
id: int,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:detail"]))],
id: Annotated[int, Path(description="工单ID")],
) -> JSONResponse:
result = await TicketService(auth).detail(id=id)
return SuccessResponse(data=result, msg="查询成功")
@TicketRouter.post("/create", summary="创建工单", response_model=ResponseSchema[TicketOutSchema])
async def ticket_create_controller(
data: TicketCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:create"]))],
data: Annotated[TicketCreateSchema, Body(description="工单创建参数")],
) -> JSONResponse:
result = await TicketService(auth).create(data=data)
return SuccessResponse(data=result, msg="创建成功")
@TicketRouter.put("/update/{id}", summary="更新工单", response_model=ResponseSchema[TicketOutSchema])
async def ticket_update_controller(
id: int,
data: TicketUpdateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:update"]))],
id: Annotated[int, Path(description="工单ID")],
data: Annotated[TicketUpdateSchema, Body(description="工单更新参数")],
) -> JSONResponse:
result = await TicketService(auth).update(id=id, data=data)
return SuccessResponse(data=result, msg="更新成功")
@TicketRouter.put("/batch", summary="批量更新工单", response_model=ResponseSchema)
async def ticket_batch_update_controller(
data: TicketBatchSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:update"]))],
data: Annotated[TicketBatchSchema, Body(description="工单批量更新参数")],
) -> JSONResponse:
await TicketService(auth).batch(data=data)
return SuccessResponse(msg="批量操作成功")
@TicketRouter.delete("/delete", summary="删除工单", response_model=ResponseSchema[None])
async def ticket_delete_controller(
ids: list[int],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:ticket:delete"]))],
ids: Annotated[list[int], Body(description="工单ID列表")],
) -> JSONResponse:
await TicketService(auth).delete(ids=ids)
return SuccessResponse(msg="删除成功")
@@ -1,7 +1,7 @@
import urllib.parse
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path, UploadFile
from fastapi import APIRouter, Body, Depends, Path, Query, File, UploadFile
from fastapi.responses import JSONResponse, StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
@@ -45,8 +45,8 @@ async def get_current_user_info_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def update_current_user_info_controller(
data: CurrentUserUpdateSchema,
auth: Annotated[AuthSchema, Depends(get_current_user)],
data: Annotated[CurrentUserUpdateSchema, Body(description="更新用户基本信息参数")],
) -> JSONResponse:
result_dict = await UserService(auth).update_current_info(data=data)
return SuccessResponse(data=result_dict, msg="更新当前用户基本信息成功")
@@ -57,8 +57,8 @@ async def update_current_user_info_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def change_current_user_password_controller(
data: UserChangePasswordSchema,
auth: Annotated[AuthSchema, Depends(get_current_user)],
data: Annotated[UserChangePasswordSchema, Body(description="修改用户密码参数")],
) -> JSONResponse:
result_dict = await UserService(auth).change_password(data=data)
return SuccessResponse(data=result_dict, msg="修改密码成功, 请重新登录")
@@ -69,9 +69,9 @@ async def change_current_user_password_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def reset_password_controller(
id: Annotated[int, Path(description="用户ID")],
data: ResetPasswordSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:update"]))],
id: Annotated[int, Path(description="用户ID")],
data: Annotated[ResetPasswordSchema, Body(description="重置用户密码参数")],
) -> JSONResponse:
data.id = id
result_dict = await UserService(auth).reset_password(data=data)
@@ -83,8 +83,8 @@ async def reset_password_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def register_user_controller(
data: UserRegisterSchema,
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[UserRegisterSchema, Body(description="注册用户参数")],
) -> JSONResponse:
auth = AuthSchema(db=db, check_data_scope=False)
user_register_result = await UserService(auth).register(data=data)
@@ -97,8 +97,8 @@ async def register_user_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def forget_password_controller(
data: UserForgetPasswordSchema,
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[UserForgetPasswordSchema, Body(description="忘记密码参数")],
) -> JSONResponse:
auth = AuthSchema(db=db, check_data_scope=False)
user_forget_password_result = await UserService(auth).forget_password(data=data)
@@ -111,9 +111,9 @@ async def forget_password_controller(
response_model=ResponseSchema[PageResultSchema[UserOutSchema]],
)
async def get_user_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[UserQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:query"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[UserQueryParam, Query(description="用户查询参数")],
) -> JSONResponse:
result_dict = await UserService(auth).page(
page_no=page.page_no,
@@ -129,8 +129,8 @@ async def get_user_list_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def get_user_detail_controller(
id: Annotated[int, Path(description="用户ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:detail"]))],
id: Annotated[int, Path(description="用户ID")],
) -> JSONResponse:
result_dict = await UserService(auth).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取用户详情成功")
@@ -141,8 +141,8 @@ async def get_user_detail_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def create_user_controller(
data: UserCreateSchema,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:create"]))],
data: Annotated[UserCreateSchema, Body(description="创建用户参数")],
) -> JSONResponse:
result_dict = await UserService(auth).create(data=data)
return SuccessResponse(data=result_dict, msg="创建用户成功")
@@ -153,9 +153,9 @@ async def create_user_controller(
response_model=ResponseSchema[UserOutSchema],
)
async def update_user_controller(
data: UserUpdateSchema,
id: Annotated[int, Path(description="用户ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:update"]))],
id: Annotated[int, Path(description="用户ID")],
data: Annotated[UserUpdateSchema, Body(description="修改用户参数")],
) -> JSONResponse:
result_dict = await UserService(auth).update(id=id, data=data)
return SuccessResponse(data=result_dict, msg="修改用户成功")
@@ -166,8 +166,8 @@ async def update_user_controller(
response_model=ResponseSchema[None],
)
async def delete_user_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:delete"]))],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await UserService(auth).delete(ids=ids)
return SuccessResponse(msg="删除用户成功")
@@ -178,8 +178,8 @@ async def delete_user_controller(
response_model=ResponseSchema[None],
)
async def batch_set_available_user_controller(
data: BatchSetAvailable,
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:patch"]))],
data: Annotated[BatchSetAvailable, Body(description="批量修改用户状态参数")],
) -> JSONResponse:
await UserService(auth).set_available(data=data)
return SuccessResponse(msg="批量修改用户状态成功")
@@ -208,9 +208,9 @@ async def export_user_import_template_controller() -> StreamingResponse:
response_model=ResponseSchema[None],
)
async def export_user_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[UserQueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:export"]))],
page: Annotated[PaginationQueryParam, Query(description="分页参数")],
search: Annotated[UserQueryParam, Query(description="用户查询参数")],
) -> StreamingResponse:
user_list = await UserService(auth).get_list(search=search, order_by=page.order_by)
user_export_result = UserService.export_list(user_list=user_list)
@@ -227,7 +227,7 @@ async def export_user_list_controller(
response_model=ResponseSchema[None],
)
async def import_user_list_controller(
file: UploadFile,
file: Annotated[UploadFile, File(description="用户导入文件")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["module_system:user:import"]))],
) -> JSONResponse:
batch_import_result = await UserService(auth).batch_import(file=file, update_support=True)
@@ -1,7 +1,6 @@
import io
from typing import Any
import pandas as pd
from fastapi import UploadFile
from app.api.v1.module_platform.menu.crud import MenuCRUD
@@ -304,23 +303,26 @@ class UserService:
try:
contents = await file.read()
df = pd.read_excel(io.BytesIO(contents))
rows = ExcelUtil.read_excel_to_dicts(contents)
await file.close()
if df.empty:
if not rows:
raise CustomException(msg="导入文件为空")
missing_headers = [header for header in header_dict if header not in df.columns]
missing_headers = [h for h in header_dict if h not in rows[0]]
if missing_headers:
raise CustomException(msg=f"导入文件缺少必要的列: {', '.join(missing_headers)}")
df.rename(columns=header_dict, inplace=True)
# 将中文字段名映射为英文字段
mapped_rows = []
for row in rows:
mapped_rows.append({en: row.get(ch) for ch, en in header_dict.items()})
required_fields = ["username", "name", "dept_id"]
errors = []
for field in required_fields:
if df[field].isnull().any():
missing_count = df[field].isnull().sum()
missing_count = sum(1 for r in mapped_rows if r.get(field) is None)
if missing_count:
errors.append(f"字段'{field}'{missing_count}行缺少数据")
if errors:
@@ -329,10 +331,10 @@ class UserService:
success_count = 0
error_msgs = []
for i, (_, row) in enumerate(df.iterrows(), start=2):
for i, row in enumerate(mapped_rows, start=2):
try:
username = str(row["username"]).strip() if pd.notna(row["username"]) else ""
name = str(row["name"]).strip() if pd.notna(row["name"]) else ""
username = (str(row["username"]) if row["username"] is not None else "").strip()
name = (str(row["name"]) if row["name"] is not None else "").strip()
if not username:
error_msgs.append(f"{i}行: 账号不能为空")
continue
@@ -343,9 +345,9 @@ class UserService:
user_data = {
"username": username,
"name": name,
"email": str(row["email"]).strip() if pd.notna(row["email"]) else None,
"mobile": str(row["mobile"]).strip() if pd.notna(row["mobile"]) else None,
"gender": str(row["gender"]).strip() if pd.notna(row["gender"]) else "1",
"email": str(row["email"]).strip() if row.get("email") is not None else None,
"mobile": str(row["mobile"]).strip() if row.get("mobile") is not None else None,
"gender": str(row["gender"]).strip() if row.get("gender") is not None else "1",
"status": 0 if str(row["status"]).strip() == "正常" else 1,
"dept_id": int(row["dept_id"]),
"password": PwdUtil.hash_password(password="123456"),