初始提交

This commit is contained in:
焦龙言
2026-07-24 09:43:10 +08:00
commit b5b4721456
793 changed files with 116305 additions and 0 deletions
@@ -0,0 +1,129 @@
from typing import Annotated
from fastapi import Path, Request, Response
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.router import APIRouterPro
from common.vo import DataResponseModel, ResponseBaseModel
from module_admin.entity.vo.cache_vo import CacheInfoModel, CacheMonitorModel
from module_admin.service.cache_service import CacheService
from utils.log_util import logger
from utils.response_util import ResponseUtil
cache_controller = APIRouterPro(
prefix='/monitor/cache', order_num=15, tags=['系统监控-缓存监控'], dependencies=[PreAuthDependency()]
)
@cache_controller.get(
'',
summary='获取缓存监控信息接口',
description='用于获取缓存监控信息',
response_model=DataResponseModel[CacheMonitorModel],
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
async def get_monitor_cache_info(request: Request) -> Response:
# 获取全量数据
cache_info_query_result = await CacheService.get_cache_monitor_statistical_info_services(request)
logger.info('获取成功')
return ResponseUtil.success(data=cache_info_query_result)
@cache_controller.get(
'/getNames',
summary='获取缓存名称列表接口',
description='用于获取缓存名称列表',
response_model=DataResponseModel[list[CacheInfoModel]],
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
async def get_monitor_cache_name(request: Request) -> Response:
# 获取全量数据
cache_name_list_result = await CacheService.get_cache_monitor_cache_name_services()
logger.info('获取成功')
return ResponseUtil.success(data=cache_name_list_result)
@cache_controller.get(
'/getKeys/{cache_name}',
summary='获取缓存键列表接口',
description='用于获取指定缓存名称下的所有缓存键列表',
response_model=DataResponseModel[list[str]],
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
async def get_monitor_cache_key(request: Request, cache_name: Annotated[str, Path(description='缓存名称')]) -> Response:
# 获取全量数据
cache_key_list_result = await CacheService.get_cache_monitor_cache_key_services(request, cache_name)
logger.info('获取成功')
return ResponseUtil.success(data=cache_key_list_result)
@cache_controller.get(
'/getValue/{cache_name}/{cache_key}',
summary='获取缓存值接口',
description='用于获取指定缓存名称下的指定缓存键对应的值',
response_model=DataResponseModel[CacheInfoModel],
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
async def get_monitor_cache_value(
request: Request,
cache_name: Annotated[str, Path(description='缓存名称')],
cache_key: Annotated[str, Path(description='缓存键')],
) -> Response:
# 获取全量数据
cache_value_list_result = await CacheService.get_cache_monitor_cache_value_services(request, cache_name, cache_key)
logger.info('获取成功')
return ResponseUtil.success(data=cache_value_list_result)
@cache_controller.delete(
'/clearCacheName/{cache_name}',
summary='清除缓存名称接口',
description='用于清除指定缓存名称下的所有缓存键值对',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_CACHE_CLEAR_NAME, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
async def clear_monitor_cache_name(
request: Request, cache_name: Annotated[str, Path(description='缓存名称')]
) -> Response:
clear_cache_name_result = await CacheService.clear_cache_monitor_cache_name_services(request, cache_name)
logger.info(clear_cache_name_result.message)
return ResponseUtil.success(msg=clear_cache_name_result.message)
@cache_controller.delete(
'/clearCacheKey/{cache_key}',
summary='清除缓存键接口',
description='用于清除指定缓存键对应的值',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_CACHE_CLEAR_KEY, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
async def clear_monitor_cache_key(request: Request, cache_key: Annotated[str, Path(description='缓存键')]) -> Response:
clear_cache_key_result = await CacheService.clear_cache_monitor_cache_key_services(request, cache_key)
logger.info(clear_cache_key_result.message)
return ResponseUtil.success(msg=clear_cache_key_result.message)
@cache_controller.delete(
'/clearCacheAll',
summary='清除所有缓存接口',
description='用于清除所有缓存键值对',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:cache:list')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_CACHE_CLEAR_ALL, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
async def clear_monitor_cache_all(request: Request) -> Response:
clear_cache_all_result = await CacheService.clear_cache_monitor_all_services(request)
logger.info(clear_cache_all_result.message)
return ResponseUtil.success(msg=clear_cache_all_result.message)
@@ -0,0 +1,46 @@
import uuid
from datetime import timedelta
from fastapi import Request, Response
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.constant import ApiNamespace
from common.enums import RedisInitKeyConfig
from common.router import APIRouterPro
from common.vo import DynamicResponseModel
from module_admin.entity.vo.login_vo import CaptchaCode
from module_admin.service.captcha_service import CaptchaService
from utils.log_util import logger
from utils.response_util import ResponseUtil
captcha_controller = APIRouterPro(order_num=2, tags=['验证码模块'])
@captcha_controller.get(
'/captchaImage',
summary='获取图片验证码接口',
description='用于获取图片验证码',
response_model=DynamicResponseModel[CaptchaCode],
)
@ApiRateLimit(namespace=ApiNamespace.CAPTCHA_IMAGE, preset=ApiRateLimitPreset.ANON_AUTH_CAPTCHA)
async def get_captcha_image(request: Request) -> Response:
captcha_enabled = (
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true'
)
register_enabled = (
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.registerUser') == 'true'
)
session_id = str(uuid.uuid4())
captcha_result = await CaptchaService.create_captcha_image_service()
image = captcha_result[0]
computed_result = captcha_result[1]
await request.app.state.redis.set(
f'{RedisInitKeyConfig.CAPTCHA_CODES.key}:{session_id}', computed_result, ex=timedelta(minutes=2)
)
logger.info(f'编号为{session_id}的会话获取图片验证码成功')
return ResponseUtil.success(
model_content=CaptchaCode(
captchaEnabled=captcha_enabled, registerEnabled=register_enabled, img=image, uuid=session_id
)
)
@@ -0,0 +1,77 @@
from typing import Annotated
from fastapi import BackgroundTasks, File, Query, Request, Response, UploadFile
from fastapi.responses import StreamingResponse
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.router import APIRouterPro
from common.vo import DynamicResponseModel
from module_admin.entity.vo.common_vo import UploadResponseModel
from module_admin.service.common_service import CommonService
from utils.log_util import logger
from utils.response_util import ResponseUtil
common_controller = APIRouterPro(prefix='/common', order_num=16, tags=['通用模块'], dependencies=[PreAuthDependency()])
@common_controller.post(
'/upload',
summary='通用文件上传接口',
description='用于上传文件',
response_model=DynamicResponseModel[UploadResponseModel],
)
@ApiRateLimit(namespace=ApiNamespace.COMMON_UPLOAD, preset=ApiRateLimitPreset.COMMON_UPLOAD)
async def common_upload(request: Request, file: Annotated[UploadFile, File(...)]) -> Response:
upload_result = await CommonService.upload_service(request, file)
logger.info('上传成功')
return ResponseUtil.success(model_content=upload_result.result)
@common_controller.get(
'/download',
summary='通用文件下载接口',
description='用于下载下载目录中的文件',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回文件',
'content': {
'application/octet-stream': {},
},
}
},
)
async def common_download(
request: Request,
background_tasks: BackgroundTasks,
file_name: Annotated[str, Query(alias='fileName')],
delete: Annotated[bool, Query()],
) -> Response:
download_result = await CommonService.download_services(background_tasks, file_name, delete)
logger.info(download_result.message)
return ResponseUtil.streaming(data=download_result.result)
@common_controller.get(
'/download/resource',
summary='通用资源文件下载接口',
description='用于下载上传目录中的资源文件',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回文件',
'content': {
'application/octet-stream': {},
},
}
},
)
async def common_download_resource(request: Request, resource: Annotated[str, Query()]) -> Response:
download_resource_result = await CommonService.download_resource_services(resource)
logger.info(download_resource_result.message)
return ResponseUtil.streaming(data=download_resource_result.result)
@@ -0,0 +1,201 @@
from datetime import datetime
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.config_vo import ConfigModel, ConfigPageQueryModel, DeleteConfigModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.config_service import ConfigService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
config_controller = APIRouterPro(
prefix='/system/config', order_num=9, tags=['系统管理-参数管理'], dependencies=[PreAuthDependency()]
)
@config_controller.get(
'/list',
summary='获取参数分页列表接口',
description='用于获取参数分页列表',
response_model=PageResponseModel[ConfigModel],
dependencies=[UserInterfaceAuthDependency('system:config:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_CONFIG_LIST)
async def get_system_config_list(
request: Request,
config_page_query: Annotated[ConfigPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
config_page_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=config_page_query_result)
@config_controller.post(
'',
summary='新增参数接口',
description='用于新增参数',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:config:add')],
)
@ValidateFields(validate_model='add_config')
@ApiCacheEvict(namespaces=ApiGroup.CONFIG_MUTATION)
@Log(title='参数管理', business_type=BusinessType.INSERT)
async def add_system_config(
request: Request,
add_config: ConfigModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_config.create_by = current_user.user.user_name
add_config.create_time = datetime.now()
add_config.update_by = current_user.user.user_name
add_config.update_time = datetime.now()
add_config_result = await ConfigService.add_config_services(request, query_db, add_config)
logger.info(add_config_result.message)
return ResponseUtil.success(msg=add_config_result.message)
@config_controller.put(
'',
summary='编辑参数接口',
description='用于编辑参数',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:config:edit')],
)
@ValidateFields(validate_model='edit_config')
@ApiCacheEvict(namespaces=ApiGroup.CONFIG_MUTATION)
@Log(title='参数管理', business_type=BusinessType.UPDATE)
async def edit_system_config(
request: Request,
edit_config: ConfigModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_config.update_by = current_user.user.user_name
edit_config.update_time = datetime.now()
edit_config_result = await ConfigService.edit_config_services(request, query_db, edit_config)
logger.info(edit_config_result.message)
return ResponseUtil.success(msg=edit_config_result.message)
@config_controller.delete(
'/refreshCache',
summary='刷新参数缓存接口',
description='用于刷新参数缓存',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:config:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_CONFIG_REFRESH_CACHE, preset=ApiRateLimitPreset.USER_COMMON_MUTATION)
@Log(title='参数管理', business_type=BusinessType.UPDATE)
async def refresh_system_config(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
refresh_config_result = await ConfigService.refresh_sys_config_services(request, query_db)
logger.info(refresh_config_result.message)
return ResponseUtil.success(msg=refresh_config_result.message)
@config_controller.delete(
'/{config_ids}',
summary='删除参数接口',
description='用于删除参数',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:config:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.CONFIG_MUTATION)
@Log(title='参数管理', business_type=BusinessType.DELETE)
async def delete_system_config(
request: Request,
config_ids: Annotated[str, Path(description='需要删除的参数主键')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_config = DeleteConfigModel(configIds=config_ids)
delete_config_result = await ConfigService.delete_config_services(request, query_db, delete_config)
logger.info(delete_config_result.message)
return ResponseUtil.success(msg=delete_config_result.message)
@config_controller.get(
'/{config_id}',
summary='获取参数详情接口',
description='用于获取指定参数的详细信息',
response_model=DataResponseModel[ConfigModel],
dependencies=[UserInterfaceAuthDependency('system:config:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_CONFIG_DETAIL)
async def query_detail_system_config(
request: Request,
config_id: Annotated[int, Path(description='参数主键')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
config_detail_result = await ConfigService.config_detail_services(query_db, config_id)
logger.info(f'获取config_id为{config_id}的信息成功')
return ResponseUtil.success(data=config_detail_result)
@config_controller.get(
'/configKey/{config_key}',
summary='根据参数键查询参数值接口',
description='用于根据参数键从缓存中查询参数值',
response_model=ResponseBaseModel,
)
async def query_system_config(request: Request, config_key: str) -> Response:
# 获取全量数据
config_query_result = await ConfigService.query_config_list_from_cache_services(request.app.state.redis, config_key)
logger.info('获取成功')
return ResponseUtil.success(msg=config_query_result)
@config_controller.post(
'/export',
summary='导出参数列表接口',
description='用于导出当前符合查询条件的参数列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回参数列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:config:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_CONFIG_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='参数管理', business_type=BusinessType.EXPORT)
async def export_system_config_list(
request: Request,
config_page_query: Annotated[ConfigPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
config_query_result = await ConfigService.get_config_list_services(query_db, config_page_query, is_page=False)
config_export_result = await ConfigService.export_config_list_services(config_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(config_export_result))
@@ -0,0 +1,175 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from pydantic_validation_decorator import ValidateFields
from sqlalchemy import ColumnElement
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.aspect.data_scope import DataScopeDependency
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, ResponseBaseModel
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.vo.dept_vo import DeleteDeptModel, DeptModel, DeptQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.dept_service import DeptService
from utils.log_util import logger
from utils.response_util import ResponseUtil
dept_controller = APIRouterPro(
prefix='/system/dept', order_num=6, tags=['系统管理-部门管理'], dependencies=[PreAuthDependency()]
)
@dept_controller.get(
'/list/exclude/{dept_id}',
summary='获取编辑部门的下拉树接口',
description='用于获取部门下拉树,不包含指定部门及其子部门',
response_model=DataResponseModel[list[DeptModel]],
dependencies=[UserInterfaceAuthDependency('system:dept:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DEPT_EDIT_TREE)
async def get_system_dept_tree_for_edit_option(
request: Request,
dept_id: Annotated[int, Path(description='部门id')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
dept_query = DeptModel(deptId=dept_id)
dept_query_result = await DeptService.get_dept_for_edit_option_services(query_db, dept_query, data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@dept_controller.get(
'/list',
summary='获取部门列表接口',
description='用于获取部门列表',
response_model=DataResponseModel[list[DeptModel]],
dependencies=[UserInterfaceAuthDependency('system:dept:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DEPT_LIST)
async def get_system_dept_list(
request: Request,
dept_query: Annotated[DeptQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
dept_query_result = await DeptService.get_dept_list_services(query_db, dept_query, data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@dept_controller.post(
'',
summary='新增部门接口',
description='用于新增部门',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dept:add')],
)
@ValidateFields(validate_model='add_dept')
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='部门管理', business_type=BusinessType.INSERT)
async def add_system_dept(
request: Request,
add_dept: DeptModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_dept.create_by = current_user.user.user_name
add_dept.create_time = datetime.now()
add_dept.update_by = current_user.user.user_name
add_dept.update_time = datetime.now()
add_dept_result = await DeptService.add_dept_services(query_db, add_dept)
logger.info(add_dept_result.message)
return ResponseUtil.success(msg=add_dept_result.message)
@dept_controller.put(
'',
summary='编辑部门接口',
description='用于编辑部门',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dept:edit')],
)
@ValidateFields(validate_model='edit_dept')
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='部门管理', business_type=BusinessType.UPDATE)
async def edit_system_dept(
request: Request,
edit_dept: DeptModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, edit_dept.dept_id, data_scope_sql)
edit_dept.update_by = current_user.user.user_name
edit_dept.update_time = datetime.now()
edit_dept_result = await DeptService.edit_dept_services(query_db, edit_dept)
logger.info(edit_dept_result.message)
return ResponseUtil.success(msg=edit_dept_result.message)
@dept_controller.delete(
'/{dept_ids}',
summary='删除部门接口',
description='用于删除部门',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dept:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='部门管理', business_type=BusinessType.DELETE)
async def delete_system_dept(
request: Request,
dept_ids: Annotated[str, Path(description='需要删除的部门id')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
dept_id_list = dept_ids.split(',') if dept_ids else []
if dept_id_list:
for dept_id in dept_id_list:
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, int(dept_id), data_scope_sql)
delete_dept = DeleteDeptModel(deptIds=dept_ids)
delete_dept.update_by = current_user.user.user_name
delete_dept.update_time = datetime.now()
delete_dept_result = await DeptService.delete_dept_services(query_db, delete_dept)
logger.info(delete_dept_result.message)
return ResponseUtil.success(msg=delete_dept_result.message)
@dept_controller.get(
'/{dept_id}',
summary='获取部门详情接口',
description='用于获取指定部门的详情信息',
response_model=DataResponseModel[DeptModel],
dependencies=[UserInterfaceAuthDependency('system:dept:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DEPT_DETAIL)
async def query_detail_system_dept(
request: Request,
dept_id: Annotated[int, Path(description='部门id')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, dept_id, data_scope_sql)
detail_dept_result = await DeptService.dept_detail_services(query_db, dept_id)
logger.info(f'获取dept_id为{dept_id}的信息成功')
return ResponseUtil.success(data=detail_dept_result)
@@ -0,0 +1,377 @@
from datetime import datetime
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.dict_vo import (
DeleteDictDataModel,
DeleteDictTypeModel,
DictDataModel,
DictDataPageQueryModel,
DictTypeModel,
DictTypePageQueryModel,
)
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.dict_service import DictDataService, DictTypeService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
dict_controller = APIRouterPro(
prefix='/system/dict', order_num=8, tags=['系统管理-字典管理'], dependencies=[PreAuthDependency()]
)
@dict_controller.get(
'/type/list',
summary='获取字典类型分页列表接口',
description='用于获取字典类型分页列表',
response_model=PageResponseModel[DictTypeModel],
dependencies=[UserInterfaceAuthDependency('system:dict:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DICT_TYPE_LIST)
async def get_system_dict_type_list(
request: Request,
dict_type_page_query: Annotated[DictTypePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
dict_type_page_query_result = await DictTypeService.get_dict_type_list_services(
query_db, dict_type_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=dict_type_page_query_result)
@dict_controller.post(
'/type',
summary='新增字典类型接口',
description='用于新增字典类型',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:add')],
)
@ValidateFields(validate_model='add_dict_type')
@ApiCacheEvict(namespaces=ApiGroup.DICT_TYPE_MUTATION)
@Log(title='字典类型', business_type=BusinessType.INSERT)
async def add_system_dict_type(
request: Request,
add_dict_type: DictTypeModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_dict_type.create_by = current_user.user.user_name
add_dict_type.create_time = datetime.now()
add_dict_type.update_by = current_user.user.user_name
add_dict_type.update_time = datetime.now()
add_dict_type_result = await DictTypeService.add_dict_type_services(request, query_db, add_dict_type)
logger.info(add_dict_type_result.message)
return ResponseUtil.success(msg=add_dict_type_result.message)
@dict_controller.put(
'/type',
summary='编辑字典类型接口',
description='用于编辑字典类型',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:edit')],
)
@ValidateFields(validate_model='edit_dict_type')
@ApiCacheEvict(namespaces=ApiGroup.DICT_TYPE_MUTATION)
@Log(title='字典类型', business_type=BusinessType.UPDATE)
async def edit_system_dict_type(
request: Request,
edit_dict_type: DictTypeModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_dict_type.update_by = current_user.user.user_name
edit_dict_type.update_time = datetime.now()
edit_dict_type_result = await DictTypeService.edit_dict_type_services(request, query_db, edit_dict_type)
logger.info(edit_dict_type_result.message)
return ResponseUtil.success(msg=edit_dict_type_result.message)
@dict_controller.delete(
'/type/refreshCache',
summary='刷新字典缓存接口',
description='用于刷新字典缓存',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_DICT_REFRESH_CACHE, preset=ApiRateLimitPreset.USER_COMMON_MUTATION)
@Log(title='字典类型', business_type=BusinessType.UPDATE)
async def refresh_system_dict(request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]) -> Response:
refresh_dict_result = await DictTypeService.refresh_sys_dict_services(request, query_db)
logger.info(refresh_dict_result.message)
return ResponseUtil.success(msg=refresh_dict_result.message)
@dict_controller.delete(
'/type/{dict_ids}',
summary='删除字典类型接口',
description='用于删除字典类型',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.DICT_TYPE_MUTATION)
@Log(title='字典类型', business_type=BusinessType.DELETE)
async def delete_system_dict_type(
request: Request,
dict_ids: Annotated[str, Path(description='需要删除的字典主键')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_dict_type = DeleteDictTypeModel(dictIds=dict_ids)
delete_dict_type_result = await DictTypeService.delete_dict_type_services(request, query_db, delete_dict_type)
logger.info(delete_dict_type_result.message)
return ResponseUtil.success(msg=delete_dict_type_result.message)
@dict_controller.get(
'/type/optionselect',
summary='获取字典类型下拉列表接口',
description='用于获取字典类型下拉列表',
response_model=DataResponseModel[list[DictTypeModel]],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DICT_TYPE_OPTIONS)
async def query_system_dict_type_options(
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
) -> Response:
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
query_db, DictTypePageQueryModel(), is_page=False
)
logger.info('获取成功')
return ResponseUtil.success(data=dict_type_query_result)
@dict_controller.get(
'/type/{dict_id}',
summary='获取字典类型详情接口',
description='用于获取指定字典类型的详细信息',
response_model=DataResponseModel[DictTypeModel],
dependencies=[UserInterfaceAuthDependency('system:dict:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DICT_TYPE_DETAIL)
async def query_detail_system_dict_type(
request: Request,
dict_id: Annotated[int, Path(description='字典主键')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
dict_type_detail_result = await DictTypeService.dict_type_detail_services(query_db, dict_id)
logger.info(f'获取dict_id为{dict_id}的信息成功')
return ResponseUtil.success(data=dict_type_detail_result)
@dict_controller.post(
'/type/export',
summary='导出字典类型列表接口',
description='用于导出当前符合查询条件的字典类型列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回字典类型列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:dict:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_DICT_TYPE_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='字典类型', business_type=BusinessType.EXPORT)
async def export_system_dict_type_list(
request: Request,
dict_type_page_query: Annotated[DictTypePageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
dict_type_query_result = await DictTypeService.get_dict_type_list_services(
query_db, dict_type_page_query, is_page=False
)
dict_type_export_result = await DictTypeService.export_dict_type_list_services(dict_type_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(dict_type_export_result))
@dict_controller.get(
'/data/type/{dict_type}',
summary='获取指定字典类型的数据列表接口',
description='用于从缓存中获取指定字典类型的所有数据项',
response_model=DataResponseModel[list[DictDataModel]],
)
async def query_system_dict_type_data(
request: Request,
dict_type: Annotated[str, Path(description='字典类型')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
dict_data_query_result = await DictDataService.query_dict_data_list_from_cache_services(
request.app.state.redis, dict_type
)
logger.info('获取成功')
return ResponseUtil.success(data=dict_data_query_result)
@dict_controller.get(
'/data/list',
summary='获取字典数据分页列表接口',
description='用于获取字典数据分页列表',
response_model=PageResponseModel[DictDataModel],
dependencies=[UserInterfaceAuthDependency('system:dict:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DICT_DATA_LIST)
async def get_system_dict_data_list(
request: Request,
dict_data_page_query: Annotated[DictDataPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
dict_data_page_query_result = await DictDataService.get_dict_data_list_services(
query_db, dict_data_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=dict_data_page_query_result)
@dict_controller.post(
'/data',
summary='新增字典数据接口',
description='用于新增字典数据',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:add')],
)
@ValidateFields(validate_model='add_dict_data')
@ApiCacheEvict(namespaces=ApiGroup.DICT_DATA_MUTATION)
@Log(title='字典数据', business_type=BusinessType.INSERT)
async def add_system_dict_data(
request: Request,
add_dict_data: DictDataModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_dict_data.create_by = current_user.user.user_name
add_dict_data.create_time = datetime.now()
add_dict_data.update_by = current_user.user.user_name
add_dict_data.update_time = datetime.now()
add_dict_data_result = await DictDataService.add_dict_data_services(request, query_db, add_dict_data)
logger.info(add_dict_data_result.message)
return ResponseUtil.success(msg=add_dict_data_result.message)
@dict_controller.put(
'/data',
summary='编辑字典数据接口',
description='用于编辑字典数据',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:edit')],
)
@ValidateFields(validate_model='edit_dict_data')
@ApiCacheEvict(namespaces=ApiGroup.DICT_DATA_MUTATION)
@Log(title='字典数据', business_type=BusinessType.UPDATE)
async def edit_system_dict_data(
request: Request,
edit_dict_data: DictDataModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_dict_data.update_by = current_user.user.user_name
edit_dict_data.update_time = datetime.now()
edit_dict_data_result = await DictDataService.edit_dict_data_services(request, query_db, edit_dict_data)
logger.info(edit_dict_data_result.message)
return ResponseUtil.success(msg=edit_dict_data_result.message)
@dict_controller.delete(
'/data/{dict_codes}',
summary='删除字典数据接口',
description='用于删除字典数据',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:dict:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.DICT_DATA_MUTATION)
@Log(title='字典数据', business_type=BusinessType.DELETE)
async def delete_system_dict_data(
request: Request,
dict_codes: Annotated[str, Path(description='需要删除的字典编码')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_dict_data = DeleteDictDataModel(dictCodes=dict_codes)
delete_dict_data_result = await DictDataService.delete_dict_data_services(request, query_db, delete_dict_data)
logger.info(delete_dict_data_result.message)
return ResponseUtil.success(msg=delete_dict_data_result.message)
@dict_controller.get(
'/data/{dict_code}',
summary='获取字典数据详情接口',
description='用于获取指定字典数据的详细信息',
response_model=DataResponseModel[DictDataModel],
dependencies=[UserInterfaceAuthDependency('system:dict:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_DICT_DATA_DETAIL)
async def query_detail_system_dict_data(
request: Request,
dict_code: Annotated[int, Path(description='字典编码')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
detail_dict_data_result = await DictDataService.dict_data_detail_services(query_db, dict_code)
logger.info(f'获取dict_code为{dict_code}的信息成功')
return ResponseUtil.success(data=detail_dict_data_result)
@dict_controller.post(
'/data/export',
summary='导出字典数据列表接口',
description='用于导出当前符合查询条件的字典数据列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回字典数据列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:dict:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_DICT_DATA_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='字典数据', business_type=BusinessType.EXPORT)
async def export_system_dict_data_list(
request: Request,
dict_data_page_query: Annotated[DictDataPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
dict_data_query_result = await DictDataService.get_dict_data_list_services(
query_db, dict_data_page_query, is_page=False
)
dict_data_export_result = await DictDataService.export_dict_data_list_services(dict_data_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(dict_data_export_result))
@@ -0,0 +1,318 @@
from datetime import datetime
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.job_vo import (
DeleteJobLogModel,
DeleteJobModel,
EditJobModel,
JobLogModel,
JobLogPageQueryModel,
JobModel,
JobPageQueryModel,
)
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.job_log_service import JobLogService
from module_admin.service.job_service import JobService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
job_controller = APIRouterPro(
prefix='/monitor', order_num=13, tags=['系统监控-定时任务'], dependencies=[PreAuthDependency()]
)
@job_controller.get(
'/job/list',
summary='获取定时任务分页列表接口',
description='用于获取定时任务分页列表',
response_model=PageResponseModel[JobModel],
dependencies=[UserInterfaceAuthDependency('monitor:job:list')],
)
@ApiCache(namespace=ApiNamespace.MONITOR_JOB_LIST)
async def get_system_job_list(
request: Request,
job_page_query: Annotated[JobPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
job_page_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=job_page_query_result)
@job_controller.post(
'/job',
summary='新增定时任务接口',
description='用于新增定时任务',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:add')],
)
@ValidateFields(validate_model='add_job')
@ApiCacheEvict(namespaces=ApiGroup.JOB_MUTATION)
@Log(title='定时任务', business_type=BusinessType.INSERT)
async def add_system_job(
request: Request,
add_job: JobModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_job.create_by = current_user.user.user_name
add_job.create_time = datetime.now()
add_job.update_by = current_user.user.user_name
add_job.update_time = datetime.now()
add_job_result = await JobService.add_job_services(query_db, add_job)
logger.info(add_job_result.message)
return ResponseUtil.success(msg=add_job_result.message)
@job_controller.put(
'/job',
summary='编辑定时任务接口',
description='用于编辑定时任务',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:edit')],
)
@ValidateFields(validate_model='edit_job')
@ApiCacheEvict(namespaces=ApiGroup.JOB_MUTATION)
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def edit_system_job(
request: Request,
edit_job: EditJobModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_job.update_by = current_user.user.user_name
edit_job.update_time = datetime.now()
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
logger.info(edit_job_result.message)
return ResponseUtil.success(msg=edit_job_result.message)
@job_controller.put(
'/job/changeStatus',
summary='修改定时任务状态接口',
description='用于修改定时任务状态',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:changeStatus')],
)
@ApiCacheEvict(namespaces=ApiGroup.JOB_MUTATION)
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def change_system_job_status(
request: Request,
change_job: EditJobModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_job = EditJobModel(
jobId=change_job.job_id,
status=change_job.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_job_result = await JobService.edit_job_services(query_db, edit_job)
logger.info(edit_job_result.message)
return ResponseUtil.success(msg=edit_job_result.message)
@job_controller.put(
'/job/run',
summary='执行定时任务接口',
description='用于执行指定的定时任务',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:changeStatus')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_RUN, preset=ApiRateLimitPreset.USER_RESOURCE_EXECUTION)
@ApiCacheEvict(namespaces=ApiGroup.JOB_MUTATION)
@Log(title='定时任务', business_type=BusinessType.UPDATE)
async def execute_system_job(
request: Request,
execute_job: JobModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
execute_job_result = await JobService.execute_job_once_services(query_db, execute_job)
logger.info(execute_job_result.message)
return ResponseUtil.success(msg=execute_job_result.message)
@job_controller.delete(
'/job/{job_ids}',
summary='删除定时任务接口',
description='用于删除定时任务',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_DELETE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@ApiCacheEvict(namespaces=ApiGroup.JOB_MUTATION)
@Log(title='定时任务', business_type=BusinessType.DELETE)
async def delete_system_job(
request: Request,
job_ids: Annotated[str, Path(description='需要删除的定时任务ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_job = DeleteJobModel(jobIds=job_ids)
delete_job_result = await JobService.delete_job_services(query_db, delete_job)
logger.info(delete_job_result.message)
return ResponseUtil.success(msg=delete_job_result.message)
@job_controller.get(
'/job/{job_id}',
summary='获取定时任务详情接口',
description='用于获取指定定时任务的详情信息',
response_model=DataResponseModel[JobModel],
dependencies=[UserInterfaceAuthDependency('monitor:job:query')],
)
@ApiCache(namespace=ApiNamespace.MONITOR_JOB_DETAIL)
async def query_detail_system_job(
request: Request,
job_id: Annotated[int, Path(description='任务ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
job_detail_result = await JobService.job_detail_services(query_db, job_id)
logger.info(f'获取job_id为{job_id}的信息成功')
return ResponseUtil.success(data=job_detail_result)
@job_controller.post(
'/job/export',
summary='导出定时任务列表接口',
description='用于导出当前符合查询条件的定时任务列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回定时任务列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('monitor:job:export')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='定时任务', business_type=BusinessType.EXPORT)
async def export_system_job_list(
request: Request,
job_page_query: Annotated[JobPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
job_query_result = await JobService.get_job_list_services(query_db, job_page_query, is_page=False)
job_export_result = await JobService.export_job_list_services(request, job_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(job_export_result))
@job_controller.get(
'/jobLog/list',
summary='获取定时任务调度日志分页列表接口',
description='用于获取定时任务调度日志分页列表',
response_model=PageResponseModel[JobLogModel],
dependencies=[UserInterfaceAuthDependency('monitor:job:list')],
)
async def get_system_job_log_list(
request: Request,
job_log_page_query: Annotated[JobLogPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
job_log_page_query_result = await JobLogService.get_job_log_list_services(
query_db, job_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=job_log_page_query_result)
@job_controller.delete(
'/jobLog/clean',
summary='清空定时任务调度日志接口',
description='用于清空所有定时任务调度日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_LOG_CLEAN, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='定时任务调度日志', business_type=BusinessType.CLEAN)
async def clear_system_job_log(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
clear_job_log_result = await JobLogService.clear_job_log_services(query_db)
logger.info(clear_job_log_result.message)
return ResponseUtil.success(msg=clear_job_log_result.message)
@job_controller.delete(
'/jobLog/{job_log_ids}',
summary='删除定时任务调度日志接口',
description='用于删除定时任务调度日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:job:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_LOG_DELETE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='定时任务调度日志', business_type=BusinessType.DELETE)
async def delete_system_job_log(
request: Request,
job_log_ids: Annotated[str, Path(description='需要删除的定时任务日志ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_job_log = DeleteJobLogModel(jobLogIds=job_log_ids)
delete_job_log_result = await JobLogService.delete_job_log_services(query_db, delete_job_log)
logger.info(delete_job_log_result.message)
return ResponseUtil.success(msg=delete_job_log_result.message)
@job_controller.post(
'/jobLog/export',
summary='导出定时任务调度日志列表接口',
description='用于导出当前符合查询条件的定时任务调度日志列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回定时任务日志列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('monitor:job:export')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_JOB_LOG_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='定时任务调度日志', business_type=BusinessType.EXPORT)
async def export_system_job_log_list(
request: Request,
job_log_page_query: Annotated[JobLogPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
job_log_query_result = await JobLogService.get_job_log_list_services(query_db, job_log_page_query, is_page=False)
job_log_export_result = await JobLogService.export_job_log_list_services(request, job_log_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(job_log_export_result))
@@ -0,0 +1,241 @@
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.log_vo import (
DeleteLoginLogModel,
DeleteOperLogModel,
LogininforModel,
LoginLogPageQueryModel,
OperLogModel,
OperLogPageQueryModel,
UnlockUser,
)
from module_admin.service.log_service import LoginLogService, OperationLogService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
log_controller = APIRouterPro(
prefix='/monitor', order_num=11, tags=['系统管理-日志管理'], dependencies=[PreAuthDependency()]
)
@log_controller.get(
'/operlog/list',
summary='获取操作日志分页列表接口',
description='用于获取操作日志分页列表',
response_model=PageResponseModel[OperLogModel],
dependencies=[UserInterfaceAuthDependency('monitor:operlog:list')],
)
async def get_system_operation_log_list(
request: Request,
operation_log_page_query: Annotated[OperLogPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
operation_log_page_query_result = await OperationLogService.get_operation_log_list_services(
query_db, operation_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=operation_log_page_query_result)
@log_controller.delete(
'/operlog/clean',
summary='清空操作日志接口',
description='用于清空所有操作日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:operlog:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_OPERLOG_CLEAN, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='操作日志', business_type=BusinessType.CLEAN)
async def clear_system_operation_log(
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
) -> Response:
clear_operation_log_result = await OperationLogService.clear_operation_log_services(query_db)
logger.info(clear_operation_log_result.message)
return ResponseUtil.success(msg=clear_operation_log_result.message)
@log_controller.delete(
'/operlog/{oper_ids}',
summary='删除操作日志接口',
description='用于删除操作日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:operlog:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_OPERLOG_DELETE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='操作日志', business_type=BusinessType.DELETE)
async def delete_system_operation_log(
request: Request,
oper_ids: Annotated[str, Path(description='需要删除的日志主键')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_operation_log = DeleteOperLogModel(operIds=oper_ids)
delete_operation_log_result = await OperationLogService.delete_operation_log_services(
query_db, delete_operation_log
)
logger.info(delete_operation_log_result.message)
return ResponseUtil.success(msg=delete_operation_log_result.message)
@log_controller.post(
'/operlog/export',
summary='导出操作日志接口',
description='用于导出当前符合查询条件的操作日志数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回操作日志列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('monitor:operlog:export')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_OPERLOG_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='操作日志', business_type=BusinessType.EXPORT)
async def export_system_operation_log_list(
request: Request,
operation_log_page_query: Annotated[OperLogPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
operation_log_query_result = await OperationLogService.get_operation_log_list_services(
query_db, operation_log_page_query, is_page=False
)
operation_log_export_result = await OperationLogService.export_operation_log_list_services(
request, operation_log_query_result
)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(operation_log_export_result))
@log_controller.get(
'/logininfor/list',
summary='获取登录日志分页列表接口',
description='用于获取登录日志分页列表',
response_model=PageResponseModel[LogininforModel],
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:list')],
)
async def get_system_login_log_list(
request: Request,
login_log_page_query: Annotated[LoginLogPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
login_log_page_query_result = await LoginLogService.get_login_log_list_services(
query_db, login_log_page_query, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=login_log_page_query_result)
@log_controller.delete(
'/logininfor/clean',
summary='清空登录日志接口',
description='用于清空所有登录日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_LOGININFO_CLEAN, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='登录日志', business_type=BusinessType.CLEAN)
async def clear_system_login_log(
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
) -> Response:
clear_login_log_result = await LoginLogService.clear_login_log_services(query_db)
logger.info(clear_login_log_result.message)
return ResponseUtil.success(msg=clear_login_log_result.message)
@log_controller.delete(
'/logininfor/{info_ids}',
summary='删除登录日志接口',
description='用于删除登录日志',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:remove')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_LOGININFO_DELETE, preset=ApiRateLimitPreset.USER_DESTRUCTIVE_MUTATION)
@Log(title='登录日志', business_type=BusinessType.DELETE)
async def delete_system_login_log(
request: Request,
info_ids: Annotated[str, Path(description='需要删除的访问ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_login_log = DeleteLoginLogModel(infoIds=info_ids)
delete_login_log_result = await LoginLogService.delete_login_log_services(query_db, delete_login_log)
logger.info(delete_login_log_result.message)
return ResponseUtil.success(msg=delete_login_log_result.message)
@log_controller.get(
'/logininfor/unlock/{user_name}',
summary='解锁账户接口',
description='用于解锁指定用户账户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:unlock')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_LOGININFO_UNLOCK, preset=ApiRateLimitPreset.USER_SECURITY_MUTATION)
@Log(title='账户解锁', business_type=BusinessType.OTHER)
async def unlock_system_user(
request: Request,
user_name: Annotated[str, Path(description='用户名称')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
unlock_user = UnlockUser(userName=user_name)
unlock_user_result = await LoginLogService.unlock_user_services(request, unlock_user)
logger.info(unlock_user_result.message)
return ResponseUtil.success(msg=unlock_user_result.message)
@log_controller.post(
'/logininfor/export',
summary='导出登录日志接口',
description='用于导出当前符合查询条件的登录日志数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回登录日志列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('monitor:logininfor:export')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_LOGININFO_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='登录日志', business_type=BusinessType.EXPORT)
async def export_system_login_log_list(
request: Request,
login_log_page_query: Annotated[LoginLogPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
login_log_query_result = await LoginLogService.get_login_log_list_services(
query_db, login_log_page_query, is_page=False
)
login_log_export_result = await LoginLogService.export_login_log_list_services(login_log_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(login_log_export_result))
@@ -0,0 +1,192 @@
import uuid
from datetime import datetime, timedelta
from typing import Annotated
import jwt
from fastapi import Depends, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.pre_auth import CurrentUserDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType, RedisInitKeyConfig
from common.router import APIRouterPro
from common.vo import CrudResponseModel, DataResponseModel, DynamicResponseModel, ResponseBaseModel
from config.env import AppConfig, JwtConfig
from module_admin.entity.vo.login_vo import LoginToken, RouterModel, Token, UserLogin, UserRegister
from module_admin.entity.vo.user_vo import CurrentUserModel, EditUserModel
from module_admin.service.login_service import CustomOAuth2PasswordRequestForm, LoginService, oauth2_scheme
from module_admin.service.user_service import UserService
from utils.log_util import logger
from utils.response_util import ResponseUtil
login_controller = APIRouterPro(order_num=1, tags=['登录模块'])
@login_controller.post(
'/login',
summary='登录接口',
description='用于用户登录',
response_model=DynamicResponseModel[LoginToken] | Token,
)
@ApiRateLimit(namespace=ApiNamespace.LOGIN, preset=ApiRateLimitPreset.ANON_AUTH_LOGIN)
@ApiCacheEvict(namespaces=ApiGroup.LOGIN_SUCCESS_MUTATION)
@Log(title='用户登录', business_type=BusinessType.OTHER, log_type='login')
async def login(
request: Request,
form_data: Annotated[CustomOAuth2PasswordRequestForm, Depends()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
captcha_enabled = (
await request.app.state.redis.get(f'{RedisInitKeyConfig.SYS_CONFIG.key}:sys.account.captchaEnabled') == 'true'
)
user = UserLogin(
userName=form_data.username,
password=form_data.password,
code=form_data.code,
uuid=form_data.uuid,
loginInfo=form_data.login_info,
captchaEnabled=captcha_enabled,
)
result = await LoginService.authenticate_user(request, query_db, user)
access_token_expires = timedelta(minutes=JwtConfig.jwt_expire_minutes)
session_id = str(uuid.uuid4())
access_token = await LoginService.create_access_token(
data={
'user_id': str(result[0].user_id),
'user_name': result[0].user_name,
'dept_name': result[1].dept_name if result[1] else None,
'session_id': session_id,
'login_info': user.login_info,
},
expires_delta=access_token_expires,
)
if AppConfig.app_same_time_login:
await request.app.state.redis.set(
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{session_id}',
access_token,
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
)
else:
# 此方法可实现同一账号同一时间只能登录一次
await request.app.state.redis.set(
f'{RedisInitKeyConfig.ACCESS_TOKEN.key}:{result[0].user_id}',
access_token,
ex=timedelta(minutes=JwtConfig.jwt_redis_expire_minutes),
)
await UserService.edit_user_services(
query_db, EditUserModel(userId=result[0].user_id, loginDate=datetime.now(), type='status')
)
logger.info('登录成功')
# 判断请求是否来自于api文档,如果是返回指定格式的结果,用于修复api文档认证成功后token显示undefined的bug
request_from_swagger = request.headers.get('referer').endswith('docs') if request.headers.get('referer') else False
request_from_redoc = request.headers.get('referer').endswith('redoc') if request.headers.get('referer') else False
if request_from_swagger or request_from_redoc:
return {'access_token': access_token, 'token_type': 'Bearer'}
return ResponseUtil.success(msg='登录成功', dict_content={'token': access_token})
@login_controller.get(
'/getInfo',
summary='获取用户信息接口',
description='用于获取当前登录用户的信息',
response_model=DynamicResponseModel[CurrentUserModel],
)
@ApiCache(namespace=ApiNamespace.LOGIN_USER_INFO)
async def get_login_user_info(
request: Request, current_user: Annotated[CurrentUserModel, CurrentUserDependency()]
) -> Response:
logger.info('获取成功')
return ResponseUtil.success(model_content=current_user)
@login_controller.get(
'/getRouters',
summary='获取用户路由接口',
description='用于获取当前登录用户的路由信息',
response_model=DataResponseModel[list[RouterModel]],
)
@ApiCache(namespace=ApiNamespace.LOGIN_USER_ROUTERS)
async def get_login_user_routers(
request: Request,
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
logger.info('获取成功')
user_routers = await LoginService.get_current_user_routers(current_user.user.user_id, query_db)
return ResponseUtil.success(data=user_routers)
@login_controller.post(
'/register',
summary='注册接口',
description='用于用户注册',
response_model=DataResponseModel[CrudResponseModel],
)
@ApiRateLimit(namespace=ApiNamespace.REGISTER, preset=ApiRateLimitPreset.ANON_AUTH_REGISTER)
@ApiCacheEvict(namespaces=ApiGroup.USER_ENTITY_MUTATION)
async def register_user(
request: Request,
user_register: UserRegister,
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
user_register_result = await LoginService.register_user_services(request, query_db, user_register)
logger.info(user_register_result.message)
return ResponseUtil.success(data=user_register_result, msg=user_register_result.message)
# @login_controller.post("/getSmsCode", response_model=SmsCode)
# async def get_sms_code(request: Request, user: ResetUserModel, query_db: AsyncSession = DBSessionDependency()):
# try:
# sms_result = await LoginService.get_sms_code_services(request, query_db, user)
# if sms_result.is_success:
# logger.info('获取成功')
# return ResponseUtil.success(data=sms_result)
# else:
# logger.warning(sms_result.message)
# return ResponseUtil.failure(msg=sms_result.message)
# except Exception as e:
# logger.exception(e)
# return ResponseUtil.error(msg=str(e))
#
#
# @login_controller.post("/forgetPwd", response_model=CrudResponseModel)
# async def forget_user_pwd(request: Request, forget_user: ResetUserModel, query_db: AsyncSession = DBSessionDependency()):
# try:
# forget_user_result = await LoginService.forget_user_services(request, query_db, forget_user)
# if forget_user_result.is_success:
# logger.info(forget_user_result.message)
# return ResponseUtil.success(data=forget_user_result, msg=forget_user_result.message)
# else:
# logger.warning(forget_user_result.message)
# return ResponseUtil.failure(msg=forget_user_result.message)
# except Exception as e:
# logger.exception(e)
# return ResponseUtil.error(msg=str(e))
@login_controller.post(
'/logout',
summary='退出登录接口',
description='用于用户退出登录',
response_model=ResponseBaseModel,
)
@ApiCacheEvict(namespaces=ApiGroup.LOGOUT_MUTATION)
async def logout(request: Request, token: Annotated[str | None, Depends(oauth2_scheme)]) -> Response:
payload = jwt.decode(
token, JwtConfig.jwt_secret_key, algorithms=[JwtConfig.jwt_algorithm], options={'verify_exp': False}
)
if AppConfig.app_same_time_login:
token_id: str = payload.get('session_id')
else:
token_id: str = payload.get('user_id')
await LoginService.logout_services(request, token_id)
logger.info('退出成功')
return ResponseUtil.success(msg='退出成功')
@@ -0,0 +1,173 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, DynamicResponseModel, ResponseBaseModel
from module_admin.entity.vo.menu_vo import DeleteMenuModel, MenuModel, MenuQueryModel, MenuTreeModel
from module_admin.entity.vo.role_vo import RoleMenuQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.menu_service import MenuService
from utils.log_util import logger
from utils.response_util import ResponseUtil
menu_controller = APIRouterPro(
prefix='/system/menu', order_num=5, tags=['系统管理-菜单管理'], dependencies=[PreAuthDependency()]
)
@menu_controller.get(
'/treeselect',
summary='获取菜单树接口',
description='用于获取当前用户可见的菜单树',
response_model=DataResponseModel[list[MenuTreeModel]],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_MENU_TREE)
async def get_system_menu_tree(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
menu_query_result = await MenuService.get_menu_tree_services(query_db, current_user)
logger.info('获取成功')
return ResponseUtil.success(data=menu_query_result)
@menu_controller.get(
'/roleMenuTreeselect/{role_id}',
summary='获取角色菜单树接口',
description='用于获取指定角色可见的菜单树',
response_model=DynamicResponseModel[RoleMenuQueryModel],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_MENU_ROLE_TREE)
async def get_system_role_menu_tree(
request: Request,
role_id: Annotated[int, Path(description='角色ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
role_menu_query_result = await MenuService.get_role_menu_tree_services(query_db, role_id, current_user)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_menu_query_result)
@menu_controller.get(
'/list',
summary='获取菜单列表接口',
description='用于获取当前用户可见的菜单列表',
response_model=DataResponseModel[list[MenuModel]],
dependencies=[UserInterfaceAuthDependency('system:menu:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_MENU_LIST)
async def get_system_menu_list(
request: Request,
menu_query: Annotated[MenuQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
menu_query_result = await MenuService.get_menu_list_services(query_db, menu_query, current_user)
logger.info('获取成功')
return ResponseUtil.success(data=menu_query_result)
@menu_controller.post(
'',
summary='新增菜单接口',
description='用于新增菜单',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:menu:add')],
)
@ValidateFields(validate_model='add_menu')
@ApiCacheEvict(namespaces=ApiGroup.MENU_MUTATION)
@Log(title='菜单管理', business_type=BusinessType.INSERT)
async def add_system_menu(
request: Request,
add_menu: MenuModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_menu.create_by = current_user.user.user_name
add_menu.create_time = datetime.now()
add_menu.update_by = current_user.user.user_name
add_menu.update_time = datetime.now()
add_menu_result = await MenuService.add_menu_services(query_db, add_menu)
logger.info(add_menu_result.message)
return ResponseUtil.success(msg=add_menu_result.message)
@menu_controller.put(
'',
summary='编辑菜单接口',
description='用于编辑菜单',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:menu:edit')],
)
@ValidateFields(validate_model='edit_menu')
@ApiCacheEvict(namespaces=ApiGroup.MENU_MUTATION)
@Log(title='菜单管理', business_type=BusinessType.UPDATE)
async def edit_system_menu(
request: Request,
edit_menu: MenuModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_menu.update_by = current_user.user.user_name
edit_menu.update_time = datetime.now()
edit_menu_result = await MenuService.edit_menu_services(query_db, edit_menu)
logger.info(edit_menu_result.message)
return ResponseUtil.success(msg=edit_menu_result.message)
@menu_controller.delete(
'/{menu_ids}',
summary='删除菜单接口',
description='用于删除菜单',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:menu:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.MENU_MUTATION)
@Log(title='菜单管理', business_type=BusinessType.DELETE)
async def delete_system_menu(
request: Request,
menu_ids: Annotated[str, Path(description='需要删除的菜单ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_menu = DeleteMenuModel(menuIds=menu_ids)
delete_menu_result = await MenuService.delete_menu_services(query_db, delete_menu)
logger.info(delete_menu_result.message)
return ResponseUtil.success(msg=delete_menu_result.message)
@menu_controller.get(
'/{menu_id}',
summary='获取菜单详情接口',
description='用于获取指定菜单的详情信息',
response_model=DataResponseModel[MenuModel],
dependencies=[UserInterfaceAuthDependency('system:menu:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_MENU_DETAIL)
async def query_detail_system_menu(
request: Request,
menu_id: Annotated[int, Path(description='菜单ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
menu_detail_result = await MenuService.menu_detail_services(query_db, menu_id)
logger.info(f'获取menu_id为{menu_id}的信息成功')
return ResponseUtil.success(data=menu_detail_result)
@@ -0,0 +1,135 @@
from datetime import datetime
from typing import Annotated
from fastapi import Path, Query, Request, Response
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.notice_vo import DeleteNoticeModel, NoticeModel, NoticePageQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.notice_service import NoticeService
from utils.log_util import logger
from utils.response_util import ResponseUtil
notice_controller = APIRouterPro(
prefix='/system/notice', order_num=10, tags=['系统管理-通知公告管理'], dependencies=[PreAuthDependency()]
)
@notice_controller.get(
'/list',
summary='获取通知公告分页列表接口',
description='用于获取通知公告分页列表',
response_model=PageResponseModel[NoticeModel],
dependencies=[UserInterfaceAuthDependency('system:notice:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_NOTICE_LIST)
async def get_system_notice_list(
request: Request,
notice_page_query: Annotated[NoticePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
notice_page_query_result = await NoticeService.get_notice_list_services(query_db, notice_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=notice_page_query_result)
@notice_controller.post(
'',
summary='新增通知公告接口',
description='用于新增通知公告',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:notice:add')],
)
@ValidateFields(validate_model='add_notice')
@ApiCacheEvict(namespaces=ApiGroup.NOTICE_MUTATION)
@Log(title='通知公告', business_type=BusinessType.INSERT)
async def add_system_notice(
request: Request,
add_notice: NoticeModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_notice.create_by = current_user.user.user_name
add_notice.create_time = datetime.now()
add_notice.update_by = current_user.user.user_name
add_notice.update_time = datetime.now()
add_notice_result = await NoticeService.add_notice_services(query_db, add_notice)
logger.info(add_notice_result.message)
return ResponseUtil.success(msg=add_notice_result.message)
@notice_controller.put(
'',
summary='编辑通知公告接口',
description='用于编辑通知公告',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:notice:edit')],
)
@ValidateFields(validate_model='edit_notice')
@ApiCacheEvict(namespaces=ApiGroup.NOTICE_MUTATION)
@Log(title='通知公告', business_type=BusinessType.UPDATE)
async def edit_system_notice(
request: Request,
edit_notice: NoticeModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_notice.update_by = current_user.user.user_name
edit_notice.update_time = datetime.now()
edit_notice_result = await NoticeService.edit_notice_services(query_db, edit_notice)
logger.info(edit_notice_result.message)
return ResponseUtil.success(msg=edit_notice_result.message)
@notice_controller.delete(
'/{notice_ids}',
summary='删除通知公告接口',
description='用于删除通知公告',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:notice:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.NOTICE_MUTATION)
@Log(title='通知公告', business_type=BusinessType.DELETE)
async def delete_system_notice(
request: Request,
notice_ids: Annotated[str, Path(description='需要删除的公告ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_notice = DeleteNoticeModel(noticeIds=notice_ids)
delete_notice_result = await NoticeService.delete_notice_services(query_db, delete_notice)
logger.info(delete_notice_result.message)
return ResponseUtil.success(msg=delete_notice_result.message)
@notice_controller.get(
'/{notice_id}',
summary='获取通知公告详情接口',
description='用于获取指定通知公告的详细信息',
response_model=DataResponseModel[NoticeModel],
dependencies=[UserInterfaceAuthDependency('system:notice:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_NOTICE_DETAIL)
async def query_detail_system_post(
request: Request,
notice_id: Annotated[int, Path(description='公告ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
notice_detail_result = await NoticeService.notice_detail_services(query_db, notice_id)
logger.info(f'获取notice_id为{notice_id}的信息成功')
return ResponseUtil.success(data=notice_detail_result)
@@ -0,0 +1,63 @@
from typing import Annotated
from fastapi import Path, Query, Request, Response
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import ResponseBaseModel
from module_admin.entity.vo.online_vo import DeleteOnlineModel, OnlinePageResponseModel, OnlineQueryModel
from module_admin.service.online_service import OnlineService
from utils.log_util import logger
from utils.response_util import ResponseUtil
online_controller = APIRouterPro(
prefix='/monitor/online', order_num=12, tags=['系统监控-在线用户'], dependencies=[PreAuthDependency()]
)
@online_controller.get(
'/list',
summary='获取在线用户分页列表接口',
description='用于获取在线用户分页列表',
response_model=OnlinePageResponseModel,
dependencies=[UserInterfaceAuthDependency('monitor:online:list')],
)
async def get_monitor_online_list(
request: Request,
online_page_query: Annotated[OnlineQueryModel, Query()],
) -> Response:
# 获取全量数据
online_query_result = await OnlineService.get_online_list_services(request, online_page_query)
logger.info('获取成功')
return ResponseUtil.success(
model_content=OnlinePageResponseModel(rows=online_query_result, total=len(online_query_result))
)
@online_controller.delete(
'/{token_ids}',
summary='强退在线用户接口',
description='用于强退指定会话编号的在线用户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('monitor:online:forceLogout')],
)
@ApiRateLimit(namespace=ApiNamespace.MONITOR_ONLINE_FORCE_LOGOUT, preset=ApiRateLimitPreset.USER_SECURITY_MUTATION)
@Log(title='在线用户', business_type=BusinessType.FORCE)
async def delete_monitor_online(
request: Request,
token_ids: Annotated[str, Path(description='需要强退的会话编号')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_online = DeleteOnlineModel(tokenIds=token_ids)
delete_online_result = await OnlineService.delete_online_services(request, delete_online)
logger.info(delete_online_result.message)
return ResponseUtil.success(msg=delete_online_result.message)
@@ -0,0 +1,168 @@
from datetime import datetime
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.vo.post_vo import DeletePostModel, PostModel, PostPageQueryModel
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.service.post_service import PostService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
post_controller = APIRouterPro(
prefix='/system/post', order_num=7, tags=['系统管理-岗位管理'], dependencies=[PreAuthDependency()]
)
@post_controller.get(
'/list',
summary='获取岗位分页列表接口',
description='用于获取岗位分页列表',
response_model=PageResponseModel[PostModel],
dependencies=[UserInterfaceAuthDependency('system:post:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_POST_LIST)
async def get_system_post_list(
request: Request,
post_page_query: Annotated[PostPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取分页数据
post_page_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=True)
logger.info('获取成功')
return ResponseUtil.success(model_content=post_page_query_result)
@post_controller.post(
'',
summary='新增岗位接口',
description='用于新增岗位',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:post:add')],
)
@ValidateFields(validate_model='add_post')
@ApiCacheEvict(namespaces=ApiGroup.POST_MUTATION)
@Log(title='岗位管理', business_type=BusinessType.INSERT)
async def add_system_post(
request: Request,
add_post: PostModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_post.create_by = current_user.user.user_name
add_post.create_time = datetime.now()
add_post.update_by = current_user.user.user_name
add_post.update_time = datetime.now()
add_post_result = await PostService.add_post_services(query_db, add_post)
logger.info(add_post_result.message)
return ResponseUtil.success(msg=add_post_result.message)
@post_controller.put(
'',
summary='编辑岗位接口',
description='用于编辑岗位',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:post:edit')],
)
@ValidateFields(validate_model='edit_post')
@ApiCacheEvict(namespaces=ApiGroup.POST_MUTATION)
@Log(title='岗位管理', business_type=BusinessType.UPDATE)
async def edit_system_post(
request: Request,
edit_post: PostModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_post.update_by = current_user.user.user_name
edit_post.update_time = datetime.now()
edit_post_result = await PostService.edit_post_services(query_db, edit_post)
logger.info(edit_post_result.message)
return ResponseUtil.success(msg=edit_post_result.message)
@post_controller.delete(
'/{post_ids}',
summary='删除岗位接口',
description='用于删除岗位',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:post:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.POST_MUTATION)
@Log(title='岗位管理', business_type=BusinessType.DELETE)
async def delete_system_post(
request: Request,
post_ids: Annotated[str, Path(description='需要删除的岗位ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
delete_post = DeletePostModel(postIds=post_ids)
delete_post_result = await PostService.delete_post_services(query_db, delete_post)
logger.info(delete_post_result.message)
return ResponseUtil.success(msg=delete_post_result.message)
@post_controller.get(
'/{post_id}',
summary='获取岗位详情接口',
description='用于获取指定岗位的详细信息',
response_model=DataResponseModel[PostModel],
dependencies=[UserInterfaceAuthDependency('system:post:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_POST_DETAIL)
async def query_detail_system_post(
request: Request,
post_id: Annotated[int, Path(description='岗位ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
post_detail_result = await PostService.post_detail_services(query_db, post_id)
logger.info(f'获取post_id为{post_id}的信息成功')
return ResponseUtil.success(data=post_detail_result)
@post_controller.post(
'/export',
summary='导出岗位列表接口',
description='用于导出当前符合查询条件的岗位列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回岗位列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:post:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_POST_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='岗位管理', business_type=BusinessType.EXPORT)
async def export_system_post_list(
request: Request,
post_page_query: Annotated[PostPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
# 获取全量数据
post_query_result = await PostService.get_post_list_services(query_db, post_page_query, is_page=False)
post_export_result = await PostService.export_post_list_services(post_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(post_export_result))
@@ -0,0 +1,400 @@
from datetime import datetime
from typing import Annotated
from fastapi import Form, Path, Query, Request, Response
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy import ColumnElement
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.data_scope import DataScopeDependency
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, DynamicResponseModel, PageResponseModel, ResponseBaseModel
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.do.user_do import SysUser
from module_admin.entity.vo.dept_vo import DeptModel
from module_admin.entity.vo.role_vo import (
AddRoleModel,
DeleteRoleModel,
RoleDeptQueryModel,
RoleModel,
RolePageQueryModel,
)
from module_admin.entity.vo.user_vo import CrudUserRoleModel, CurrentUserModel, UserInfoModel, UserRolePageQueryModel
from module_admin.service.dept_service import DeptService
from module_admin.service.role_service import RoleService
from module_admin.service.user_service import UserService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.response_util import ResponseUtil
role_controller = APIRouterPro(
prefix='/system/role', order_num=4, tags=['系统管理-角色管理'], dependencies=[PreAuthDependency()]
)
@role_controller.get(
'/deptTree/{role_id}',
summary='获取自定义数据权限时可见的部门树接口',
description='用于自定义数据权限时获取当前用户可见的部门树',
response_model=DynamicResponseModel[RoleDeptQueryModel],
dependencies=[UserInterfaceAuthDependency('system:role:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_ROLE_DEPT_TREE)
async def get_system_role_dept_tree(
request: Request,
role_id: Annotated[int, Path(description='角色ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(), data_scope_sql)
role_dept_query_result = await RoleService.get_role_dept_tree_services(query_db, role_id)
role_dept_query_result.depts = dept_query_result
logger.info('获取成功')
return ResponseUtil.success(model_content=role_dept_query_result)
@role_controller.get(
'/list',
summary='获取角色分页列表接口',
description='用于获取角色分页列表',
response_model=PageResponseModel[RoleModel],
dependencies=[UserInterfaceAuthDependency('system:role:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_ROLE_LIST)
async def get_system_role_list(
request: Request,
role_page_query: Annotated[RolePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
role_page_query_result = await RoleService.get_role_list_services(
query_db, role_page_query, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_page_query_result)
@role_controller.post(
'',
summary='新增角色接口',
description='用于新增角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:add')],
)
@ValidateFields(validate_model='add_role')
@ApiCacheEvict(namespaces=ApiGroup.ROLE_ENTITY_MUTATION)
@Log(title='角色管理', business_type=BusinessType.INSERT)
async def add_system_role(
request: Request,
add_role: AddRoleModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
add_role.create_by = current_user.user.user_name
add_role.create_time = datetime.now()
add_role.update_by = current_user.user.user_name
add_role.update_time = datetime.now()
add_role_result = await RoleService.add_role_services(query_db, add_role)
logger.info(add_role_result.message)
return ResponseUtil.success(msg=add_role_result.message)
@role_controller.put(
'',
summary='编辑角色接口',
description='用于编辑角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ValidateFields(validate_model='edit_role')
@ApiCacheEvict(namespaces=ApiGroup.ROLE_PERMISSION_MUTATION)
@Log(title='角色管理', business_type=BusinessType.UPDATE)
async def edit_system_role(
request: Request,
edit_role: AddRoleModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
await RoleService.check_role_allowed_services(edit_role)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(edit_role.role_id), data_scope_sql)
edit_role.update_by = current_user.user.user_name
edit_role.update_time = datetime.now()
edit_role_result = await RoleService.edit_role_services(query_db, edit_role)
logger.info(edit_role_result.message)
return ResponseUtil.success(msg=edit_role_result.message)
@role_controller.put(
'/dataScope',
summary='编辑角色数据权限接口',
description='用于编辑角色数据权限',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def edit_system_role_datascope(
request: Request,
role_data_scope: AddRoleModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
await RoleService.check_role_allowed_services(role_data_scope)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(role_data_scope.role_id), data_scope_sql)
edit_role = AddRoleModel(
roleId=role_data_scope.role_id,
dataScope=role_data_scope.data_scope,
deptIds=role_data_scope.dept_ids,
deptCheckStrictly=role_data_scope.dept_check_strictly,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
)
role_data_scope_result = await RoleService.role_datascope_services(query_db, edit_role)
logger.info(role_data_scope_result.message)
return ResponseUtil.success(msg=role_data_scope_result.message)
@role_controller.delete(
'/{role_ids}',
summary='删除角色接口',
description='用于删除角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.ROLE_ENTITY_MUTATION)
@Log(title='角色管理', business_type=BusinessType.DELETE)
async def delete_system_role(
request: Request,
role_ids: Annotated[str, Path(description='需要删除的角色ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
role_id_list = role_ids.split(',') if role_ids else []
if role_id_list:
for role_id in role_id_list:
await RoleService.check_role_allowed_services(RoleModel(roleId=int(role_id)))
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, role_id, data_scope_sql)
delete_role = DeleteRoleModel(roleIds=role_ids, updateBy=current_user.user.user_name, updateTime=datetime.now())
delete_role_result = await RoleService.delete_role_services(query_db, delete_role)
logger.info(delete_role_result.message)
return ResponseUtil.success(msg=delete_role_result.message)
@role_controller.get(
'/{role_id}',
summary='获取角色详情接口',
description='用于获取指定角色的详细信息',
response_model=DataResponseModel[RoleModel],
dependencies=[UserInterfaceAuthDependency('system:role:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_ROLE_DETAIL)
async def query_detail_system_role(
request: Request,
role_id: Annotated[int, Path(description='角色ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(role_id), data_scope_sql)
role_detail_result = await RoleService.role_detail_services(query_db, role_id)
logger.info(f'获取role_id为{role_id}的信息成功')
return ResponseUtil.success(data=role_detail_result.model_dump(by_alias=True))
@role_controller.post(
'/export',
summary='导出角色列表接口',
description='用于导出当前符合查询条件的角色列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回角色列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:role:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_ROLE_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='角色管理', business_type=BusinessType.EXPORT)
async def export_system_role_list(
request: Request,
role_page_query: Annotated[RolePageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
# 获取全量数据
role_query_result = await RoleService.get_role_list_services(
query_db, role_page_query, data_scope_sql, is_page=False
)
role_export_result = await RoleService.export_role_list_services(role_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(role_export_result))
@role_controller.put(
'/changeStatus',
summary='修改角色状态接口',
description='用于修改角色状态',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.ROLE_MUTATION)
@Log(title='角色管理', business_type=BusinessType.UPDATE)
async def reset_system_role_status(
request: Request,
change_role: AddRoleModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
await RoleService.check_role_allowed_services(change_role)
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(change_role.role_id), data_scope_sql)
edit_role = AddRoleModel(
roleId=change_role.role_id,
status=change_role.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_role_result = await RoleService.edit_role_services(query_db, edit_role)
logger.info(edit_role_result.message)
return ResponseUtil.success(msg=edit_role_result.message)
@role_controller.get(
'/authUser/allocatedList',
summary='获取已分配用户分页列表接口',
description='用于获取指定角色已分配的用户分页列表',
response_model=PageResponseModel[UserInfoModel],
dependencies=[UserInterfaceAuthDependency('system:role:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_ROLE_ALLOCATED_USER_LIST)
async def get_system_allocated_user_list(
request: Request,
user_role: Annotated[UserRolePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
role_user_allocated_page_query_result = await RoleService.get_role_user_allocated_list_services(
query_db, user_role, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_user_allocated_page_query_result)
@role_controller.get(
'/authUser/unallocatedList',
summary='获取未分配用户分页列表接口',
description='用于获取指定角色未分配的用户分页列表',
response_model=PageResponseModel[UserInfoModel],
dependencies=[UserInterfaceAuthDependency('system:role:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_ROLE_UNALLOCATED_USER_LIST)
async def get_system_unallocated_user_list(
request: Request,
user_role: Annotated[UserRolePageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
role_user_unallocated_page_query_result = await RoleService.get_role_user_unallocated_list_services(
query_db, user_role, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=role_user_unallocated_page_query_result)
@role_controller.put(
'/authUser/selectAll',
summary='分配用户给角色接口',
description='用于给指定角色分配用户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_ROLE_AUTH_USER_SELECT_ALL, preset=ApiRateLimitPreset.USER_SECURITY_MUTATION)
@ApiCacheEvict(namespaces=ApiGroup.ROLE_MUTATION)
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def add_system_role_user(
request: Request,
add_role_user: Annotated[CrudUserRoleModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await RoleService.check_role_data_scope_services(query_db, str(add_role_user.role_id), data_scope_sql)
add_role_user_result = await UserService.add_user_role_services(query_db, add_role_user)
logger.info(add_role_user_result.message)
return ResponseUtil.success(msg=add_role_user_result.message)
@role_controller.put(
'/authUser/cancel',
summary='取消分配用户给角色接口',
description='用于取消指定用户分配给角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_ROLE_AUTH_USER_CANCEL, preset=ApiRateLimitPreset.USER_SECURITY_MUTATION)
@ApiCacheEvict(namespaces=ApiGroup.ROLE_MUTATION)
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def cancel_system_role_user(
request: Request,
cancel_user_role: CrudUserRoleModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
cancel_user_role_result = await UserService.delete_user_role_services(query_db, cancel_user_role)
logger.info(cancel_user_role_result.message)
return ResponseUtil.success(msg=cancel_user_role_result.message)
@role_controller.put(
'/authUser/cancelAll',
summary='批量取消分配用户给角色接口',
description='用于批量取消用户分配给角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:role:edit')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_ROLE_AUTH_USER_CANCEL_ALL, preset=ApiRateLimitPreset.USER_SECURITY_MUTATION)
@ApiCacheEvict(namespaces=ApiGroup.ROLE_MUTATION)
@Log(title='角色管理', business_type=BusinessType.GRANT)
async def batch_cancel_system_role_user(
request: Request,
batch_cancel_user_role: Annotated[CrudUserRoleModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
batch_cancel_user_role_result = await UserService.delete_user_role_services(query_db, batch_cancel_user_role)
logger.info(batch_cancel_user_role_result.message)
return ResponseUtil.success(msg=batch_cancel_user_role_result.message)
@@ -0,0 +1,32 @@
from fastapi import Request, Response
from common.annotation.cache_annotation import ApiCache
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.router import APIRouterPro
from common.vo import DataResponseModel
from module_admin.entity.vo.server_vo import ServerMonitorModel
from module_admin.service.server_service import ServerService
from utils.log_util import logger
from utils.response_util import ResponseUtil
server_controller = APIRouterPro(
prefix='/monitor/server', order_num=14, tags=['系统监控-服务监控'], dependencies=[PreAuthDependency()]
)
@server_controller.get(
'',
summary='获取服务器监控信息接口',
description='用于获取当前服务器的监控信息',
response_model=DataResponseModel[ServerMonitorModel],
dependencies=[UserInterfaceAuthDependency('monitor:server:list')],
)
@ApiCache(namespace=ApiNamespace.MONITOR_SERVER_INFO)
async def get_monitor_server_info(request: Request) -> Response:
# 获取全量数据
server_info_query_result = await ServerService.get_server_monitor_info()
logger.info('获取成功')
return ResponseUtil.success(data=server_info_query_result)
@@ -0,0 +1,78 @@
from fastapi import Request, Response
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitPreset
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import PreAuthDependency
from common.constant import ApiNamespace
from common.router import APIRouterPro
from common.vo import DataResponseModel
from module_admin.entity.vo.transport_crypto_vo import (
TransportCryptoFrontendConfigModel,
TransportCryptoMonitorModel,
TransportCryptoPublicKeyModel,
)
from module_admin.service.transport_crypto_service import TransportCryptoService
from utils.log_util import logger
from utils.response_util import ResponseUtil
transport_crypto_controller = APIRouterPro(prefix='/transport/crypto', order_num=15, tags=['传输加密模块'])
@transport_crypto_controller.get(
'/frontend-config',
summary='获取前端传输加密配置接口',
description='公开接口,用于向前端下发当前传输层加解密启用状态与运行模式,供前端统一跟随后端策略',
response_model=DataResponseModel[TransportCryptoFrontendConfigModel],
)
@ApiRateLimit(namespace=ApiNamespace.TRANSPORT_CRYPTO_FRONTEND_CONFIG, preset=ApiRateLimitPreset.ANON_PUBLIC_METADATA)
async def get_transport_frontend_config(request: Request) -> Response:
"""
获取当前前端传输层加解密运行配置
:param request: 当前请求对象
:return: 前端传输层加解密运行配置响应
"""
transport_frontend_config = await TransportCryptoService.get_transport_frontend_config_services()
logger.info('获取成功')
return ResponseUtil.success(data=transport_frontend_config)
@transport_crypto_controller.get(
'/public-key',
summary='获取传输加密公钥接口',
description='公开接口,用于向前端下发当前可用的传输层加密公钥,已配置匿名限流保护',
response_model=DataResponseModel[TransportCryptoPublicKeyModel],
)
@ApiRateLimit(namespace=ApiNamespace.TRANSPORT_CRYPTO_PUBLIC_KEY, preset=ApiRateLimitPreset.ANON_PUBLIC_METADATA)
async def get_transport_public_key(request: Request) -> Response:
"""
获取当前传输层加密公钥
:param request: 当前请求对象
:return: 公钥下发响应
"""
transport_public_key = await TransportCryptoService.get_transport_public_key_services()
logger.info('获取成功')
return ResponseUtil.success(data=transport_public_key)
@transport_crypto_controller.get(
'/monitor',
summary='获取传输层加解密监控信息接口',
description='用于获取基于Redis聚合的传输层加解密运行状态与统计信息',
response_model=DataResponseModel[TransportCryptoMonitorModel],
dependencies=[PreAuthDependency(), UserInterfaceAuthDependency('monitor:transportCrypto:list')],
)
async def get_transport_crypto_monitor_info(request: Request) -> Response:
"""
获取基于Redis聚合的传输层加解密监控信息
:param request: 当前请求对象
:return: 传输层加解密监控信息响应
"""
transport_crypto_monitor_info = await TransportCryptoService.get_transport_crypto_monitor_info_services(request)
logger.info('获取成功')
return ResponseUtil.success(data=transport_crypto_monitor_info)
@@ -0,0 +1,550 @@
import os
from datetime import datetime
from typing import Annotated, Literal
import aiofiles
from fastapi import File, Form, Path, Query, Request, Response, UploadFile
from fastapi.responses import StreamingResponse
from pydantic_validation_decorator import ValidateFields
from sqlalchemy import ColumnElement
from sqlalchemy.ext.asyncio import AsyncSession
from common.annotation.cache_annotation import ApiCache, ApiCacheEvict
from common.annotation.log_annotation import Log
from common.annotation.rate_limit_annotation import ApiRateLimit, ApiRateLimitBypassConfig, ApiRateLimitPreset
from common.aspect.data_scope import DataScopeDependency
from common.aspect.db_seesion import DBSessionDependency
from common.aspect.interface_auth import UserInterfaceAuthDependency
from common.aspect.pre_auth import CurrentUserDependency, PreAuthDependency
from common.constant import ApiGroup, ApiNamespace
from common.enums import BusinessType
from common.router import APIRouterPro
from common.vo import DataResponseModel, DynamicResponseModel, PageResponseModel, ResponseBaseModel
from config.env import UploadConfig
from module_admin.entity.do.dept_do import SysDept
from module_admin.entity.do.user_do import SysUser
from module_admin.entity.vo.dept_vo import DeptModel, DeptTreeModel
from module_admin.entity.vo.user_vo import (
AddUserModel,
AvatarModel,
CrudUserRoleModel,
CurrentUserModel,
DeleteUserModel,
EditUserModel,
ResetPasswordModel,
ResetUserModel,
UserDetailModel,
UserInfoModel,
UserModel,
UserPageQueryModel,
UserProfileModel,
UserRoleQueryModel,
UserRoleResponseModel,
UserRowModel,
)
from module_admin.service.dept_service import DeptService
from module_admin.service.role_service import RoleService
from module_admin.service.user_service import UserService
from utils.common_util import bytes2file_response
from utils.log_util import logger
from utils.pwd_util import PwdUtil
from utils.response_util import ResponseUtil
from utils.upload_util import UploadUtil
user_controller = APIRouterPro(
prefix='/system/user', order_num=3, tags=['系统管理-用户管理'], dependencies=[PreAuthDependency()]
)
@user_controller.get(
'/deptTree',
summary='获取部门树接口',
description='用于获取当前登录用户可见的部门树',
response_model=DataResponseModel[list[DeptTreeModel]],
dependencies=[UserInterfaceAuthDependency('system:user:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_DEPT_TREE)
async def get_system_dept_tree(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
dept_query_result = await DeptService.get_dept_tree_services(query_db, DeptModel(), data_scope_sql)
logger.info('获取成功')
return ResponseUtil.success(data=dept_query_result)
@user_controller.get(
'/list',
summary='获取用户分页列表接口',
description='用于获取用户分页列表',
response_model=PageResponseModel[UserRowModel],
dependencies=[UserInterfaceAuthDependency('system:user:list')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_LIST)
async def get_system_user_list(
request: Request,
user_page_query: Annotated[UserPageQueryModel, Query()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
# 获取分页数据
user_page_query_result = await UserService.get_user_list_services(
query_db, user_page_query, data_scope_sql, is_page=True
)
logger.info('获取成功')
return ResponseUtil.success(model_content=user_page_query_result)
@user_controller.post(
'',
summary='新增用户接口',
description='用于新增用户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:add')],
)
@ValidateFields(validate_model='add_user')
@ApiCacheEvict(namespaces=ApiGroup.USER_ENTITY_MUTATION)
@Log(title='用户管理', business_type=BusinessType.INSERT)
async def add_system_user(
request: Request,
add_user: AddUserModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await DeptService.check_dept_data_scope_services(query_db, add_user.dept_id, dept_data_scope_sql)
await RoleService.check_role_data_scope_services(
query_db, ','.join([str(item) for item in add_user.role_ids]), role_data_scope_sql
)
add_user.password = PwdUtil.get_password_hash(add_user.password)
add_user.create_by = current_user.user.user_name
add_user.create_time = datetime.now()
add_user.update_by = current_user.user.user_name
add_user.update_time = datetime.now()
add_user_result = await UserService.add_user_services(query_db, add_user)
logger.info(add_user_result.message)
return ResponseUtil.success(msg=add_user_result.message)
@user_controller.put(
'',
summary='编辑用户接口',
description='用于编辑用户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ValidateFields(validate_model='edit_user')
@ApiCacheEvict(namespaces=ApiGroup.USER_PERMISSION_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def edit_system_user(
request: Request,
edit_user: EditUserModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
await UserService.check_user_allowed_services(edit_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, edit_user.user_id, user_data_scope_sql)
await DeptService.check_dept_data_scope_services(query_db, edit_user.dept_id, dept_data_scope_sql)
await RoleService.check_role_data_scope_services(
query_db, ','.join([str(item) for item in edit_user.role_ids]), role_data_scope_sql
)
edit_user.update_by = current_user.user.user_name
edit_user.update_time = datetime.now()
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@user_controller.delete(
'/{user_ids}',
summary='删除用户接口',
description='用于删除用户',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:remove')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_ENTITY_MUTATION)
@Log(title='用户管理', business_type=BusinessType.DELETE)
async def delete_system_user(
request: Request,
user_ids: Annotated[str, Path(description='需要删除的用户ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
user_id_list = user_ids.split(',') if user_ids else []
if user_id_list:
if current_user.user.user_id in list(map(int, user_id_list)):
logger.warning('当前登录用户不能删除')
return ResponseUtil.failure(msg='当前登录用户不能删除')
for user_id in user_id_list:
await UserService.check_user_allowed_services(UserModel(userId=int(user_id)))
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, int(user_id), data_scope_sql)
delete_user = DeleteUserModel(userIds=user_ids, updateBy=current_user.user.user_name, updateTime=datetime.now())
delete_user_result = await UserService.delete_user_services(query_db, delete_user)
logger.info(delete_user_result.message)
return ResponseUtil.success(msg=delete_user_result.message)
@user_controller.put(
'/resetPwd',
summary='重置用户密码接口',
description='用于重置用户密码',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:resetPwd')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def reset_system_user_pwd(
request: Request,
reset_user: EditUserModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
await UserService.check_user_allowed_services(reset_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, reset_user.user_id, data_scope_sql)
edit_user = EditUserModel(
userId=reset_user.user_id,
password=PwdUtil.get_password_hash(reset_user.password),
pwdUpdateDate=datetime.now(),
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='pwd',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@user_controller.put(
'/changeStatus',
summary='修改用户状态接口',
description='用于修改用户状态',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='用户管理', business_type=BusinessType.UPDATE)
async def change_system_user_status(
request: Request,
change_user: EditUserModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
await UserService.check_user_allowed_services(change_user)
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, change_user.user_id, data_scope_sql)
edit_user = EditUserModel(
userId=change_user.user_id,
status=change_user.status,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='status',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@user_controller.get(
'/profile',
summary='获取用户个人信息接口',
description='用于获取当前登录用户的个人信息',
response_model=DynamicResponseModel[UserProfileModel],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_PROFILE)
async def query_detail_system_user_profile(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
profile_user_result = await UserService.user_profile_services(query_db, current_user.user.user_id)
logger.info(f'获取user_id为{current_user.user.user_id}的信息成功')
return ResponseUtil.success(model_content=profile_user_result)
@user_controller.get(
'/{user_id}',
summary='获取用户详情接口',
description='用于获取指定用户的详情信息',
response_model=DynamicResponseModel[UserDetailModel],
dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
@user_controller.get(
'/',
summary='获取用户岗位和角色列表接口',
description='用于获取当前登录用户可见的岗位和角色列表',
response_model=DynamicResponseModel[UserDetailModel],
dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
@ApiCache(namespace=ApiNamespace.SYSTEM_USER_DETAIL)
async def query_detail_system_user(
request: Request,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
user_id: int | Literal[''] | None = '',
) -> Response:
if user_id and not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, user_id, data_scope_sql)
detail_user_result = await UserService.user_detail_services(query_db, user_id)
logger.info(f'获取user_id为{user_id}的信息成功')
return ResponseUtil.success(model_content=detail_user_result)
@user_controller.post(
'/profile/avatar',
summary='修改用户头像接口',
description='用于修改当前登录用户的头像',
response_model=DynamicResponseModel[AvatarModel],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_USER_PROFILE_AVATAR, preset=ApiRateLimitPreset.USER_RESOURCE_UPLOAD)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_avatar(
request: Request,
avatarfile: Annotated[bytes, File()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
if avatarfile:
relative_path = (
f'avatar/{datetime.now().strftime("%Y")}/{datetime.now().strftime("%m")}/{datetime.now().strftime("%d")}'
)
dir_path = os.path.join(UploadConfig.UPLOAD_PATH, relative_path)
try:
os.makedirs(dir_path)
except FileExistsError:
pass
avatar_name = f'avatar_{datetime.now().strftime("%Y%m%d%H%M%S")}{UploadConfig.UPLOAD_MACHINE}{UploadUtil.generate_random_number()}.png'
avatar_path = os.path.join(dir_path, avatar_name)
async with aiofiles.open(avatar_path, 'wb') as f:
await f.write(avatarfile)
edit_user = EditUserModel(
userId=current_user.user.user_id,
avatar=f'{UploadConfig.UPLOAD_PREFIX}/{relative_path}/{avatar_name}',
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
type='avatar',
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(model_content=AvatarModel(imgUrl=edit_user.avatar), msg=edit_user_result.message)
return ResponseUtil.failure(msg='上传图片异常,请联系管理员')
@user_controller.put(
'/profile',
summary='修改用户个人信息接口',
description='用于修改当前登录用户的个人信息',
response_model=ResponseBaseModel,
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def change_system_user_profile_info(
request: Request,
user_info: UserInfoModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
edit_user = EditUserModel(
**user_info.model_dump(exclude_unset=True, by_alias=True, exclude={'role_ids', 'post_ids'}),
userId=current_user.user.user_id,
userName=current_user.user.user_name,
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
roleIds=current_user.user.role_ids.split(',') if current_user.user.role_ids else [],
postIds=current_user.user.post_ids.split(',') if current_user.user.post_ids else [],
role=current_user.user.role,
)
edit_user_result = await UserService.edit_user_services(query_db, edit_user)
logger.info(edit_user_result.message)
return ResponseUtil.success(msg=edit_user_result.message)
@user_controller.put(
'/profile/updatePwd',
summary='修改用户密码接口',
description='用于修改当前登录用户的密码',
response_model=ResponseBaseModel,
)
@ApiCacheEvict(namespaces=ApiGroup.USER_INFO_MUTATION)
@Log(title='个人信息', business_type=BusinessType.UPDATE)
async def reset_system_user_password(
request: Request,
reset_password: ResetPasswordModel,
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
) -> Response:
reset_user = ResetUserModel(
userId=current_user.user.user_id,
oldPassword=reset_password.old_password,
password=reset_password.new_password,
pwdUpdateDate=datetime.now(),
updateBy=current_user.user.user_name,
updateTime=datetime.now(),
)
reset_user_result = await UserService.reset_user_services(query_db, reset_user)
logger.info(reset_user_result.message)
return ResponseUtil.success(msg=reset_user_result.message)
@user_controller.post(
'/importData',
summary='批量导入用户接口',
description='用于批量导入用户数据',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:import')],
)
@ApiRateLimit(
namespace=ApiNamespace.SYSTEM_USER_IMPORT,
preset=ApiRateLimitPreset.USER_RESOURCE_IMPORT,
bypass=ApiRateLimitBypassConfig(roles=('admin',)),
)
@ApiCacheEvict(namespaces=ApiGroup.DATA_SCOPE_MUTATION)
@Log(title='用户管理', business_type=BusinessType.IMPORT)
async def batch_import_system_user(
request: Request,
file: Annotated[UploadFile, File(...)],
update_support: Annotated[bool, Query(alias='updateSupport')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
dept_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
batch_import_result = await UserService.batch_import_user_services(
request, query_db, file, update_support, current_user, user_data_scope_sql, dept_data_scope_sql
)
logger.info(batch_import_result.message)
return ResponseUtil.success(msg=batch_import_result.message)
@user_controller.post(
'/importTemplate',
summary='获取用户导入模板接口',
description='用于获取用户导入模板excel文件',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回导入用户模板excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:user:import')],
)
async def export_system_user_template(
request: Request, query_db: Annotated[AsyncSession, DBSessionDependency()]
) -> Response:
user_import_template_result = await UserService.get_user_import_template_services()
logger.info('获取成功')
return ResponseUtil.streaming(data=bytes2file_response(user_import_template_result))
@user_controller.post(
'/export',
summary='导出用户列表接口',
description='用于导出当前符合查询条件的用户列表数据',
response_class=StreamingResponse,
responses={
200: {
'description': '流式返回用户列表excel文件',
'content': {
'application/octet-stream': {},
},
}
},
dependencies=[UserInterfaceAuthDependency('system:user:export')],
)
@ApiRateLimit(namespace=ApiNamespace.SYSTEM_USER_EXPORT, preset=ApiRateLimitPreset.USER_RESOURCE_EXPORT)
@Log(title='用户管理', business_type=BusinessType.EXPORT)
async def export_system_user_list(
request: Request,
user_page_query: Annotated[UserPageQueryModel, Form()],
query_db: Annotated[AsyncSession, DBSessionDependency()],
data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
) -> Response:
# 获取全量数据
user_query_result = await UserService.get_user_list_services(
query_db, user_page_query, data_scope_sql, is_page=False
)
user_export_result = await UserService.export_user_list_services(user_query_result)
logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(user_export_result))
@user_controller.get(
'/authRole/{user_id}',
summary='获取用户已分配角色列表接口',
description='用于获取指定用户已分配的角色列表',
response_model=DynamicResponseModel[UserRoleResponseModel],
dependencies=[UserInterfaceAuthDependency('system:user:query')],
)
async def get_system_allocated_role_list(
request: Request,
user_id: Annotated[int, Path(description='用户ID')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
) -> Response:
user_role_query = UserRoleQueryModel(userId=user_id)
user_role_allocated_query_result = await UserService.get_user_role_allocated_list_services(
query_db, user_role_query
)
logger.info('获取成功')
return ResponseUtil.success(model_content=user_role_allocated_query_result)
@user_controller.put(
'/authRole',
summary='给用户分配角色接口',
description='用于给指定用户分配角色',
response_model=ResponseBaseModel,
dependencies=[UserInterfaceAuthDependency('system:user:edit')],
)
@ApiCacheEvict(namespaces=ApiGroup.USER_PERMISSION_MUTATION)
@Log(title='用户管理', business_type=BusinessType.GRANT)
async def update_system_role_user(
request: Request,
user_id: Annotated[int, Query(alias='userId')],
role_ids: Annotated[str, Query(alias='roleIds')],
query_db: Annotated[AsyncSession, DBSessionDependency()],
current_user: Annotated[CurrentUserModel, CurrentUserDependency()],
user_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysUser)],
role_data_scope_sql: Annotated[ColumnElement, DataScopeDependency(SysDept)],
) -> Response:
if not current_user.user.admin:
await UserService.check_user_data_scope_services(query_db, user_id, user_data_scope_sql)
await RoleService.check_role_data_scope_services(query_db, role_ids, role_data_scope_sql)
add_user_role_result = await UserService.add_user_role_services(
query_db, CrudUserRoleModel(userId=user_id, roleIds=role_ids)
)
logger.info(add_user_role_result.message)
return ResponseUtil.success(msg=add_user_role_result.message)