chore: 清理冗余代码与配置,优化项目结构

1.  删除无用文件与废弃代码:移除locale枚举、element-plus插件、sse路由、api token模块等
2.  简化类型导入与依赖:移除大量未使用的类型导入,统一echarts导入方式
3.  优化配置与样式:调整gitignore、样式引入顺序,新增列表动画样式
4.  修复接口与模型:修正接口返回类型、查询参数配置,更新部门模型字段
5.  优化性能与体验:添加图片懒加载,优化加载逻辑与表格渲染
6.  调整环境配置:新增并更新开发/生产环境配置文件
This commit is contained in:
zhangtao
2026-07-23 20:49:52 +08:00
parent 096e2216d6
commit 0ce31936aa
360 changed files with 8072 additions and 22122 deletions
@@ -1,59 +1,21 @@
from typing import Annotated
from fastapi import APIRouter, Body, Depends, Path, Query, Security, status
from fastapi.responses import JSONResponse, StreamingResponse
from fastapi import APIRouter, Body, Depends, Path, Security
from fastapi.responses import JSONResponse
from redis.asyncio.client import Redis
from sqlalchemy.ext.asyncio import AsyncSession
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema, PaginationQueryParam
from app.common.response import ResponseSchema, SuccessResponse
from app.core.base_schema import AuthSchema
from app.core.dependencies import AuthPermission, db_getter, redis_getter
from app.core.router_class import OperationLogRoute
from app.utils.common_util import bytes2file_response
from .schema import ParamsCreateSchema, ParamsOutSchema, ParamsQueryParam, ParamsUpdateSchema
from .schema import ParamsOutSchema, ParamsUpdateSchema
from .service import ParamsService
ParamsRouter = APIRouter(route_class=OperationLogRoute, prefix="/param", tags=["参数管理"])
@ParamsRouter.get("/detail/{id}", summary="获取参数详情", response_model=ResponseSchema[ParamsOutSchema])
async def get_param_detail_controller(
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:detail"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
id: Annotated[int, Path(description="参数ID", ge=1)],
) -> JSONResponse:
result_dict = await ParamsService(auth, db).detail(id=id)
return SuccessResponse(data=result_dict, msg="获取参数详情成功")
@ParamsRouter.get("/list", summary="获取参数列表", response_model=ResponseSchema[PageResultSchema[ParamsOutSchema]])
async def get_param_list_controller(
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:query"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[ParamsQueryParam, Query()],
) -> JSONResponse:
result_dict = await ParamsService(auth, db).page(
page_no=page.page_no,
page_size=page.page_size,
search=search,
order_by=page.order_by,
)
return SuccessResponse(data=result_dict, msg="查询参数列表成功")
@ParamsRouter.post("/create", status_code=status.HTTP_201_CREATED, summary="创建参数", response_model=ResponseSchema[ParamsOutSchema])
async def create_param_controller(
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:create"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[ParamsCreateSchema, Body(description="参数创建参数")],
) -> JSONResponse:
result_dict = await ParamsService(auth, db).create(redis=redis, data=data)
return SuccessResponse(data=result_dict, msg="创建参数成功")
@ParamsRouter.put("/update/{id}", summary="修改参数", response_model=ResponseSchema[ParamsOutSchema])
async def update_param_controller(
redis: Annotated[Redis, Depends(redis_getter)],
@@ -66,45 +28,6 @@ async def update_param_controller(
return SuccessResponse(data=result_dict, msg="更新参数成功")
@ParamsRouter.delete("/delete", summary="删除参数", response_model=ResponseSchema[ParamsOutSchema])
async def delete_param_controller(
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:delete"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
ids: Annotated[list[int], Body(description="ID列表")],
) -> JSONResponse:
await ParamsService(auth, db).delete(redis=redis, ids=ids)
return SuccessResponse(msg="删除参数成功")
@ParamsRouter.patch("/status/batch", summary="批量设置参数状态", response_model=ResponseSchema)
async def batch_set_status_controller(
redis: Annotated[Redis, Depends(redis_getter)],
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:patch"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[BatchSetAvailable, Body(description="状态设置")],
) -> JSONResponse:
await ParamsService(auth, db).batch_set_status(redis=redis, ids=data.ids, status=data.status)
return SuccessResponse(msg="批量设置参数状态成功")
@ParamsRouter.post("/export", summary="导出参数")
async def export_param_list_controller(
auth: Annotated[AuthSchema, Security(AuthPermission(["module_system:param:export"]))],
db: Annotated[AsyncSession, Depends(db_getter)],
search: Annotated[ParamsQueryParam, Body()],
) -> StreamingResponse:
result_dict_list = await ParamsService(auth, db).get_list(search=search)
export_data = [item.model_dump() for item in result_dict_list]
export_result = ParamsService.export(data_list=export_data)
return StreamResponse(
data=bytes2file_response(export_result),
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": "attachment; filename=params.xlsx"},
)
@ParamsRouter.get("/info", summary="获取初始化缓存参数", response_model=ResponseSchema[list[ParamsOutSchema]])
async def get_init_config_controller(
redis: Annotated[Redis, Depends(redis_getter)],
@@ -4,10 +4,10 @@ from app.core.base_crud import CRUDBase
from app.core.base_schema import AuthSchema
from .model import ParamsModel
from .schema import ParamsCreateSchema, ParamsUpdateSchema
from .schema import ParamsUpdateSchema
class ParamsCRUD(CRUDBase[ParamsModel, ParamsCreateSchema, ParamsUpdateSchema]):
class ParamsCRUD(CRUDBase[ParamsModel, ParamsUpdateSchema, ParamsUpdateSchema]):
"""配置管理数据层"""
def __init__(self, auth: AuthSchema, db: AsyncSession) -> None:
@@ -1,19 +1,18 @@
from sqlalchemy import Boolean, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.core.base_model import ModelMixin, UserMixin
from app.core.base_model import ModelMixin
class ParamsModel(ModelMixin, UserMixin):
class ParamsModel(ModelMixin):
"""系统参数表"""
__tablename__: str = "sys_param"
__table_args__: dict[str, str] = {"comment": "系统参数表"}
__loader_options__: list[str] = ["created_by", "updated_by", "deleted_by"]
config_name: Mapped[str] = mapped_column(String(64), nullable=False, comment="参数名称")
config_key: Mapped[str] = mapped_column(String(500), nullable=False, comment="参数键名")
config_name: Mapped[str] = mapped_column(String(64), nullable=False, index=True, comment="参数名称")
config_key: Mapped[str] = mapped_column(String(500), nullable=False, index=True, comment="参数键名")
config_value: Mapped[str | None] = mapped_column(Text, comment="参数键值")
config_type: Mapped[bool] = mapped_column(Boolean, default=False, nullable=True, comment="系统内置(True:是 False:否)", index=True)
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)", index=True)
status: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="状态(0:启动 1:停用)")
description: Mapped[str | None] = mapped_column(Text, default=None, nullable=True, comment="备注")
@@ -2,11 +2,11 @@ import re
from pydantic import BaseModel, ConfigDict, Field, field_validator
from app.core.base_schema import BaseQueryParam, BaseSchema, UserByQueryParam, UserBySchema
from app.core.base_schema import BaseSchema
class ParamsCreateSchema(BaseModel):
"""参数创建模型
class ParamsBaseSchema(BaseModel):
"""参数基础字段
"""
config_name: str = Field(..., min_length=1, max_length=64, description="参数名称")
@@ -34,23 +34,13 @@ class ParamsCreateSchema(BaseModel):
return v
class ParamsUpdateSchema(ParamsCreateSchema):
class ParamsUpdateSchema(ParamsBaseSchema):
"""参数更新模型
"""
class ParamsOutSchema(ParamsCreateSchema, BaseSchema, UserBySchema):
class ParamsOutSchema(ParamsBaseSchema, BaseSchema):
"""参数响应模型
"""
model_config = ConfigDict(from_attributes=True)
class ParamsQueryParam(BaseQueryParam, UserByQueryParam):
"""参数管理查询参数
"""
config_name: str | None = Field(None, description="参数名称")
config_key: str | None = Field(None, description="参数键名", json_schema_extra={"q": "eq"})
config_type: bool | None = Field(None, description="是否系统内置(True:是 False:否)")
status: int | None = Field(None, ge=0, le=1, description="状态(0:启动 1:停用)")
@@ -5,144 +5,23 @@ from redis.asyncio.client import Redis
from sqlalchemy.ext.asyncio import AsyncSession
from app.common.enums import RedisInitKeyConfig
from app.core.base_schema import AuthSchema, PageResultSchema
from app.core.base_schema import AuthSchema
from app.core.database import async_db_session
from app.core.exceptions import CustomException
from app.core.logger import logger
from app.core.redis_crud import RedisCURD
from app.utils.common_util import search_to_dict
from app.utils.excel_util import ExcelUtil
from .crud import ParamsCRUD
from .schema import (
ParamsCreateSchema,
ParamsOutSchema,
ParamsQueryParam,
ParamsUpdateSchema,
)
from .schema import ParamsOutSchema, ParamsUpdateSchema
class ParamsService:
"""参数管理服务
设计:实例方法承载「当前用户上下文 (auth)」,``redis`` 仍是方法参数
(因为不是每个端点都用到)。调用方写法由
``ParamsService.method_service(auth=...)`` 改为 ``ParamsService(auth).method(...)``。
"""
"""参数管理服务"""
def __init__(self, auth: AuthSchema, db: AsyncSession) -> None:
self.auth = auth
self.db = db
async def detail(self, id: int) -> ParamsOutSchema:
"""获取参数详情
参数:
- id (int): 参数ID
返回:
- ParamsOutSchema: 参数响应模型
"""
obj = await ParamsCRUD(self.auth, self.db).get_or_404(id=id)
return ParamsOutSchema.model_validate(obj)
async def get_by_key(self, config_key: str) -> ParamsOutSchema:
"""根据配置键获取参数详情
参数:
- config_key (str): 参数键名
返回:
- ParamsOutSchema: 参数响应模型
"""
obj = await ParamsCRUD(self.auth, self.db).get(config_key=config_key)
if not obj:
raise CustomException(msg="该数据不存在")
return ParamsOutSchema.model_validate(obj)
async def get_list(
self,
search: ParamsQueryParam | None = None,
order_by: list[dict] | None = None,
) -> list[ParamsOutSchema]:
"""获取配置管理型列表
参数:
- search (ParamsQueryParam | None): 查询参数对象
- order_by (list[dict] | None): 排序参数列表
返回:
- list[ParamsOutSchema]: 参数响应模型列表
"""
obj_list = await ParamsCRUD(self.auth, self.db).get_list(search=search_to_dict(search), order_by=order_by)
return [ParamsOutSchema.model_validate(obj) for obj in obj_list]
async def page(
self,
page_no: int,
page_size: int,
search: ParamsQueryParam | None = None,
order_by: list[dict[str, str]] | None = None,
) -> PageResultSchema[ParamsOutSchema]:
"""分页查询系统参数(数据库 OFFSET/LIMIT)。
参数:
- page_no (int): 页码(从 1 开始)
- page_size (int): 每页条数
- search (ParamsQueryParam | None): 查询条件
- order_by (list[dict[str, str]] | None): 排序字段列表
返回:
- PageResultSchema[ParamsOutSchema]: 分页结果
"""
offset = (page_no - 1) * page_size
return await ParamsCRUD(self.auth, self.db).page(
offset=offset,
limit=page_size,
order_by=order_by or [{"id": "asc"}],
search=search_to_dict(search),
out_schema=ParamsOutSchema,
)
async def create(self, redis: Redis, data: ParamsCreateSchema) -> ParamsOutSchema:
"""创建配置管理型
参数:
- redis (Redis): Redis 客户端实例
- data (ParamsCreateSchema): 配置管理型创建模型
返回:
- ParamsOutSchema: 新创建的参数响应模型
"""
exist_obj = await ParamsCRUD(self.auth, self.db).get(config_key=data.config_key)
if exist_obj:
raise CustomException(msg="创建失败,该数据已存在")
obj = await ParamsCRUD(self.auth, self.db).create(data=data)
out = ParamsOutSchema.model_validate(obj)
# 同步redis
user = self.auth.user
if not user:
raise CustomException(msg="未登录")
redis_key = f"{RedisInitKeyConfig.SYSTEM_CONFIG.key}:{data.config_key}"
try:
redis_payload = out.model_dump(mode="json")
value = json.dumps(redis_payload, ensure_ascii=False)
result = await RedisCURD(redis).set(
key=redis_key,
value=value,
expire=None,
)
if not result:
logger.error(f"同步配置到缓存失败: {out}")
raise CustomException(msg="同步配置到缓存失败")
except Exception as e:
logger.error(f"创建字典类型失败: {e}")
raise CustomException(msg="同步配置到缓存失败") from e
return out
async def update(self, redis: Redis, id: int, data: ParamsUpdateSchema) -> ParamsOutSchema:
"""更新参数
@@ -185,98 +64,6 @@ class ParamsService:
return out
async def delete(self, redis: Redis, ids: list[int]) -> None:
"""删除配置管理型
参数:
- redis (Redis): Redis 客户端实例
- ids (list[int]): 配置管理型ID列表
返回:
- None
"""
if not ids:
raise CustomException(msg="删除失败,删除对象不能为空")
# 批量校验参数存在性
objs = await ParamsCRUD(self.auth, self.db).get_list(search={"id": ("in", ids)})
obj_map = {o.id: o for o in objs}
for pid in ids:
obj = obj_map.get(pid)
if not obj:
raise CustomException(msg="删除失败,该数据不存在")
if obj.config_type:
raise CustomException(msg=f"{obj.config_name} 删除失败,系统初始化配置不可以删除")
await ParamsCRUD(self.auth, self.db).delete(ids=ids)
# 同步删除Redis缓存(使用删除前已获取的对象信息)
user = self.auth.user
if not user:
raise CustomException(msg="未登录")
for obj in objs:
redis_key = f"{RedisInitKeyConfig.SYSTEM_CONFIG.key}:{obj.config_key}"
try:
await RedisCURD(redis).delete(redis_key)
except Exception as e:
logger.error(f"删除系统配置失败: {e}")
raise CustomException(msg="同步删除缓存失败") from e
async def batch_set_status(self, redis: Redis, ids: list[int], status: int) -> None:
"""批量设置系统参数状态
参数:
- redis: Redis 客户端(用于同步缓存)
- ids (list[int]): 系统参数ID列表
- status (int): 状态值
返回:
- None
"""
if not ids:
raise CustomException(msg="请选择要操作的数据")
# 先查参数列表获取 config_key
params = await ParamsCRUD(self.auth, self.db).get_list(search={"id": ("in", list(ids))})
await ParamsCRUD(self.auth, self.db).set(ids=ids, status=status)
# 同步删除对应 Redis 缓存
for param in params:
redis_key = f"{RedisInitKeyConfig.SYSTEM_CONFIG.key}:{param.config_key}"
try:
await RedisCURD(redis).delete(redis_key)
except Exception as e:
logger.error(f"同步删除系统配置缓存失败: {e}")
@staticmethod
def export(data_list: list[dict]) -> bytes:
"""导出参数列表(无状态工具方法)
参数:
- data_list (list[dict]): 参数字典列表
返回:
- bytes: Excel 文件字节流
"""
mapping_dict = {
"id": "编号",
"config_name": "参数名称",
"config_key": "参数键名",
"config_value": "参数键值",
"config_type": "系统内置((True:是 False:否))",
"description": "备注",
"created_time": "创建时间",
"updated_time": "更新时间",
"created_id": "创建者ID",
"updated_id": "更新者ID",
}
# 复制数据并转换状态
data = data_list.copy()
for item in data:
# 处理状态
item["config_type"] = "" if item.get("config_type") else ""
return ExcelUtil.export_list2excel(list_data=data, mapping_dict=mapping_dict)
@staticmethod
async def _load_all_configs_from_db() -> Sequence[object]:
async with async_db_session() as session, session.begin():