feat(phase4): 全部业务模块迁移到 modules/(结构迁移)
- 21 个模块目录(auth/system/dictionary/configuration/cms/member/region/link/notice/job/log/upload/index) - 每个模块 router.py(合并模块导出多个 router)/schemas.py/service.py/repository.py/models.py - routers/v1.py 与 routers/__init__.py 改为直接引用 modules,前缀与权限串原样保留 - core/middleware.py 懒加载指向 modules.system.menu / modules.log;core/redis_client.py 指向 modules.job.scheduler - apps/views|services|forms 全部改为 re-export 垫片 - 迁移后 grep 守门通过:modules/core 无 apps/extensions 残留引用 - 实测登录、27+ 模块接口、写操作 commit、操作日志落库均正常 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+2
-131
@@ -1,131 +1,2 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from sqlalchemy import and_
|
||||
|
||||
from apps.constants.constants import LOG_TYPE_LIST, LOGIN_SOURCE_LIST, LOGIN_STATUS_LIST
|
||||
from apps.constants.message import PAGE_SIZE
|
||||
from apps.models.login_log import LoginLog
|
||||
from extensions.sqlalchemy import commit_independently
|
||||
from extensions import get_db_session
|
||||
from utils import R
|
||||
from utils.ip import get_client_ip
|
||||
from utils.ip2region import get_ip_location
|
||||
from utils.ua import parse_user_agent
|
||||
from utils.request import like_contains, parse_id_list
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 核心便捷方法
|
||||
# ============================================================
|
||||
|
||||
def record_login_log(request, username, log_type, source, status, **kwargs):
|
||||
"""
|
||||
记录登录日志
|
||||
|
||||
使用独立session写入,不受请求事务commit/rollback影响。
|
||||
日志是审计数据,无论业务成功或失败都应持久化。
|
||||
|
||||
Args:
|
||||
request: FastAPI Request 对象
|
||||
username: 登录账号
|
||||
log_type: 日志类型(1-登录,2-退出)
|
||||
source: 登录来源(0-后台,1-前台)
|
||||
status: 操作状态(0-正常,1-异常)
|
||||
**kwargs: 其他可选参数
|
||||
- method: 请求方法
|
||||
- request_method: 请求方式
|
||||
- url: 请求URL
|
||||
- param: 请求参数
|
||||
- result: 返回结果
|
||||
- consume_time: 请求耗时(毫秒)
|
||||
- error: 错误信息
|
||||
"""
|
||||
try:
|
||||
# 从 request 提取信息
|
||||
ip = get_client_ip(request)
|
||||
location = get_ip_location(ip)
|
||||
ua = request.headers.get('User-Agent', '')
|
||||
os_name, browser_name = parse_user_agent(ua)
|
||||
|
||||
log = LoginLog(
|
||||
username=username,
|
||||
log_type=log_type,
|
||||
source=source,
|
||||
method=kwargs.get('method', request.method),
|
||||
request_method=kwargs.get('request_method', ''),
|
||||
url=kwargs.get('url', str(request.url)),
|
||||
param=kwargs.get('param', ''),
|
||||
result=kwargs.get('result', ''),
|
||||
ip=ip,
|
||||
location=location,
|
||||
os=os_name,
|
||||
browser=browser_name,
|
||||
consume_time=kwargs.get('consume_time', 0),
|
||||
status=status,
|
||||
error=kwargs.get('error', ''),
|
||||
)
|
||||
|
||||
commit_independently(log)
|
||||
return log
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"记录登录日志异常: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================
|
||||
# CRUD 服务
|
||||
# ============================================================
|
||||
|
||||
def get_login_log_page(request):
|
||||
db = get_db_session()
|
||||
# 页码
|
||||
page = int(request.query_params.get("pageNo", 1))
|
||||
# 每页数
|
||||
limit = int(request.query_params.get("pageSize", PAGE_SIZE))
|
||||
# 实例化查询对象
|
||||
query = db.query(LoginLog).filter(LoginLog.is_delete == 0)
|
||||
# 登录账号
|
||||
username = request.query_params.get('username')
|
||||
if username:
|
||||
query = query.filter(LoginLog.username.like(like_contains(username), escape='\\'))
|
||||
# 日志类型
|
||||
log_type = request.query_params.get('log_type')
|
||||
if log_type:
|
||||
query = query.filter(LoginLog.log_type == log_type)
|
||||
# 登录来源
|
||||
source = request.query_params.get('source')
|
||||
if source:
|
||||
query = query.filter(LoginLog.source == source)
|
||||
# 操作状态
|
||||
status = request.query_params.get('status')
|
||||
if status:
|
||||
query = query.filter(LoginLog.status == status)
|
||||
# 排序
|
||||
query = query.order_by(LoginLog.id.desc())
|
||||
# 记录总数
|
||||
count = query.count()
|
||||
# 分页查询
|
||||
log_list = query.limit(limit).offset((page - 1) * limit).all()
|
||||
# 若当前页超出末页(数据被并发删除),自动回退到第一页
|
||||
if page > 1 and not log_list:
|
||||
page = 1
|
||||
count = query.count()
|
||||
log_list = query.limit(limit).offset(0).all()
|
||||
# 实例化结果
|
||||
result = []
|
||||
if len(log_list) > 0:
|
||||
for item in log_list:
|
||||
data = item.to_dict()
|
||||
data['log_type_name'] = LOG_TYPE_LIST.get(item.log_type)
|
||||
data['source_name'] = LOGIN_SOURCE_LIST.get(item.source)
|
||||
data['status_name'] = LOGIN_STATUS_LIST.get(item.status)
|
||||
result.append(data)
|
||||
return R.ok(data=result, count=count)
|
||||
|
||||
|
||||
def delete_login_log(ids_str):
|
||||
return LoginLog.batch_delete_r(ids_str)
|
||||
# 兼容垫片:由 modules.log.service 迁移
|
||||
from modules.log.service import * # noqa: F401,F403
|
||||
|
||||
Reference in New Issue
Block a user