refactor: 大规模代码整理与功能优化

1. 重构后端API路由、CRUD与模块结构,整合日志管理,移除废弃demo代码
2. 优化前端组件类型定义、样式与路由配置,修复权限判断逻辑
3. 调整默认排序规则、滚动条样式与工具类函数,更新依赖与配置文件
4. 修复多处类型不匹配与默认值问题,完善表单与菜单验证逻辑
This commit is contained in:
zhangtao
2026-06-17 01:56:31 +08:00
parent 17b3cd0a4c
commit 73f2823692
500 changed files with 40763 additions and 26616 deletions
@@ -1,239 +1,243 @@
# -*- coding: utf-8 -*-
import urllib.parse
from typing import Annotated
from fastapi import APIRouter, Depends, UploadFile, Body, Path, Query
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi import APIRouter, Body, Depends, Path, UploadFile
from fastapi.responses import JSONResponse, StreamingResponse
from app.common.response import SuccessResponse, StreamResponse
from app.core.dependencies import AuthPermission
from app.api.v1.module_system.auth.schema import AuthSchema
from app.common.response import ResponseSchema, StreamResponse, SuccessResponse
from app.core.base_params import PaginationQueryParam
from app.core.base_schema import AuthSchema, BatchSetAvailable, PageResultSchema
from app.core.dependencies import AuthPermission
from app.core.router_class import OperationLogRoute
from app.utils.common_util import bytes2file_response
from app.core.logger import log
from app.core.base_schema import BatchSetAvailable
from .schema import {{ class_name }}CreateSchema, {{ class_name }}OutSchema, {{ class_name }}QueryParam, {{ class_name }}UpdateSchema
from .service import {{ class_name }}Service
from .schema import {{ class_name }}CreateSchema, {{ class_name }}UpdateSchema, {{ class_name }}QueryParam
# 动态路由容器前缀由 module_xxx 决定(discover: module_xxx -> /xxx)
# 对齐 module_example/demo:业务路由前缀固定为 /{module_name}
{{ class_name }}Router = APIRouter(prefix='/{{ module_name }}', tags=["{{ function_name }}模块"])
{{ class_name }}Router = APIRouter(route_class=OperationLogRoute, prefix="/{{ module_name }}", tags=["{{ function_name }}模块"])
@{{ class_name }}Router.get(
"/detail/{id}",
summary="获取{{ function_name }}详情",
description="获取{{ function_name }}详情"
response_model=ResponseSchema[{{ class_name }}OutSchema],
)
async def get_{{ business_name_slug }}_detail_controller(
id: int = Path(..., description="ID"),
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:query"]))
async def get_obj_detail_controller(
id: Annotated[int, Path(description="{{ function_name }}ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:detail"]))],
) -> JSONResponse:
"""
获取{{ function_name }}详情接口
获取{{ function_name }}详情
参数:
- id: int - 数据ID
- auth: AuthSchema - 认证信息
- id (int): {{ function_name }}ID
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含{{ function_name }}详情的JSON响应
- JSONResponse: 包含{{ function_name }}详情的JSON响应
"""
result_dict = await {{ class_name }}Service.detail_{{ business_name_slug }}_service(auth=auth, id=id)
log.info(f"获取{{ function_name }}详情成功 {id}")
result_dict = await {{ class_name }}Service.detail_service(id=id, auth=auth)
return SuccessResponse(data=result_dict, msg="获取{{ function_name }}详情成功")
@{{ class_name }}Router.get(
"/list",
summary="查询{{ function_name }}列表",
description="查询{{ function_name }}列表"
summary="分页查询{{ function_name }}",
response_model=ResponseSchema[PageResultSchema[{{ class_name }}OutSchema]],
)
async def get_{{ business_name_slug }}_list_controller(
page: PaginationQueryParam = Depends(),
search: {{ class_name }}QueryParam = Depends(),
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:query"]))
async def get_obj_list_controller(
page: Annotated[PaginationQueryParam, Depends()],
search: Annotated[{{ class_name }}QueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:query"]))],
) -> JSONResponse:
"""
查询{{ function_name }}列表接口(数据库分页)
查询{{ function_name }}列表
参数:
- page: PaginationQueryParam - 分页参数
- search: {{ class_name }}QueryParam - 查询参数
- auth: AuthSchema - 认证信息
- page (PaginationQueryParam): 分页查询参数
- search ({{ class_name }}QueryParam): 查询参数
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含{{ function_name }}列表的JSON响应
- JSONResponse: 包含{{ function_name }}列表分页信息的JSON响应
"""
result_dict = await {{ class_name }}Service.page_{{ business_name_slug }}_service(
result_dict = await {{ class_name }}Service.page_service(
auth=auth,
page_no=page.page_no if page.page_no is not None else 1,
page_size=page.page_size if page.page_size is not None else 10,
page_no=page.page_no,
page_size=page.page_size,
search=search,
order_by=page.order_by
order_by=page.order_by,
)
log.info("查询{{ function_name }}列表成功")
return SuccessResponse(data=result_dict, msg="查询{{ function_name }}列表成功")
@{{ class_name }}Router.post(
"/create",
summary="创建{{ function_name }}",
description="创建{{ function_name }}"
response_model=ResponseSchema[{{ class_name }}OutSchema],
)
async def create_{{ business_name_slug }}_controller(
async def create_obj_controller(
data: {{ class_name }}CreateSchema,
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:create"]))
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:create"]))],
) -> JSONResponse:
"""
创建{{ function_name }}接口
创建{{ function_name }}
参数:
- data: {{ class_name }}CreateSchema - 创建数据
- auth: AuthSchema - 认证信息
- data ({{ class_name }}CreateSchema): {{ function_name }}创建模型
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含创建{{ function_name }}结果的JSON响应
- JSONResponse: 包含创建{{ function_name }}详情的JSON响应
"""
result_dict = await {{ class_name }}Service.create_{{ business_name_slug }}_service(auth=auth, data=data)
log.info("创建{{ function_name }}成功")
result_dict = await {{ class_name }}Service.create_service(auth=auth, data=data)
return SuccessResponse(data=result_dict, msg="创建{{ function_name }}成功")
@{{ class_name }}Router.put(
"/update/{id}",
summary="修改{{ function_name }}",
description="修改{{ function_name }}"
response_model=ResponseSchema[{{ class_name }}OutSchema],
)
async def update_{{ business_name_slug }}_controller(
async def update_obj_controller(
data: {{ class_name }}UpdateSchema,
id: int = Path(..., description="ID"),
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:update"]))
id: Annotated[int, Path(description="{{ function_name }}ID")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:update"]))],
) -> JSONResponse:
"""
修改{{ function_name }}接口
修改{{ function_name }}
参数:
- id: int - 数据ID
- data: {{ class_name }}UpdateSchema - 更新数据
- auth: AuthSchema - 认证信息
- data ({{ class_name }}UpdateSchema): {{ function_name }}更新模型
- id (int): {{ function_name }}ID
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含修改{{ function_name }}结果的JSON响应
- JSONResponse: 包含修改{{ function_name }}详情的JSON响应
"""
result_dict = await {{ class_name }}Service.update_{{ business_name_slug }}_service(auth=auth, id=id, data=data)
log.info("修改{{ function_name }}成功")
result_dict = await {{ class_name }}Service.update_service(auth=auth, id=id, data=data)
return SuccessResponse(data=result_dict, msg="修改{{ function_name }}成功")
@{{ class_name }}Router.delete(
"/delete",
summary="删除{{ function_name }}",
description="删除{{ function_name }}"
response_model=ResponseSchema[None],
)
async def delete_{{ business_name_slug }}_controller(
ids: list[int] = Body(..., description="ID列表"),
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:delete"]))
async def delete_obj_controller(
ids: Annotated[list[int], Body(description="ID列表")],
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:delete"]))],
) -> JSONResponse:
"""
删除{{ function_name }}接口
删除{{ function_name }}
参数:
- ids: list[int] - 数据ID列表
- auth: AuthSchema - 认证信息
- ids (list[int]): {{ function_name }}ID列表
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含删除{{ function_name }}结果的JSON响应
- JSONResponse: 包含删除{{ function_name }}详情的JSON响应
"""
await {{ class_name }}Service.delete_{{ business_name_slug }}_service(auth=auth, ids=ids)
log.info(f"删除{{ function_name }}成功: {ids}")
await {{ class_name }}Service.delete_service(auth=auth, ids=ids)
return SuccessResponse(msg="删除{{ function_name }}成功")
@{{ class_name }}Router.patch(
"/status/batch",
"/available/setting",
summary="批量修改{{ function_name }}状态",
description="批量修改{{ function_name }}状态"
response_model=ResponseSchema[None],
)
async def batch_set_available_{{ business_name_slug }}_controller(
async def batch_set_available_obj_controller(
data: BatchSetAvailable,
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:patch"]))
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:patch"]))],
) -> JSONResponse:
"""
批量修改{{ function_name }}状态接口
批量修改{{ function_name }}状态
参数:
- data: BatchSetAvailable - 批量修改状态数据
- auth: AuthSchema - 认证信息
- data (BatchSetAvailable): 批量修改{{ function_name }}状态模型
- auth (AuthSchema): 认证信息模型
返回:
- JSONResponse - 包含批量修改{{ function_name }}状态结果的JSON响应
- JSONResponse: 包含批量修改{{ function_name }}状态详情的JSON响应
"""
await {{ class_name }}Service.set_available_{{ business_name_slug }}_service(auth=auth, data=data)
log.info(f"批量修改{{ function_name }}状态成功: {data.ids}")
await {{ class_name }}Service.set_available_service(auth=auth, data=data)
return SuccessResponse(msg="批量修改{{ function_name }}状态成功")
@{{ class_name }}Router.post(
'/export',
"/export",
summary="导出{{ function_name }}",
description="导出{{ function_name }}"
)
async def export_{{ business_name_slug }}_list_controller(
search: {{ class_name }}QueryParam = Depends(),
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:export"]))
async def export_obj_list_controller(
search: Annotated[{{ class_name }}QueryParam, Depends()],
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:export"]))],
) -> StreamingResponse:
"""
导出{{ function_name }}接口
导出{{ function_name }}
参数:
- search: {{ class_name }}QueryParam - 查询参数
- auth: AuthSchema - 认证信息
- search ({{ class_name }}QueryParam): 查询参数
- auth (AuthSchema): 认证信息模型
返回:
- StreamingResponse - 包含导出{{ function_name }}数据的流式响应
- StreamingResponse: 包含{{ function_name }}列表的Excel文件流响应
"""
result_dict_list = await {{ class_name }}Service.list_{{ business_name_slug }}_service(search=search, auth=auth)
export_result = await {{ class_name }}Service.batch_export_{{ business_name_slug }}_service(obj_list=result_dict_list)
log.info('导出{{ function_name }}成功')
result_dict_list = await {{ class_name }}Service.list_service(search=search, auth=auth)
export_result = await {{ class_name }}Service.batch_export_service(obj_list=result_dict_list)
return StreamResponse(
data=bytes2file_response(export_result),
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers={'Content-Disposition': 'attachment; filename={{ table_name }}.xlsx'}
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={"Content-Disposition": "attachment; filename={{ table_name }}.xlsx"},
)
@{{ class_name }}Router.post(
'/import',
summary="导入{{ function_name }}",
description="导入{{ function_name }}"
)
async def import_{{ business_name_slug }}_list_controller(
file: UploadFile,
auth: AuthSchema = Depends(AuthPermission(["{{ permission_prefix }}:import"]))
) -> JSONResponse:
"""
导入{{ function_name }}接口
参数:
- file: UploadFile - 上传的Excel文件
- auth: AuthSchema - 认证信息
返回:
- JSONResponse - 包含导入{{ function_name }}结果的JSON响应
"""
batch_import_result = await {{ class_name }}Service.batch_import_{{ business_name_slug }}_service(file=file, auth=auth, update_support=True)
log.info("导入{{ function_name }}成功")
return SuccessResponse(data=batch_import_result, msg="导入{{ function_name }}成功")
@{{ class_name }}Router.post(
'/download/template',
summary="获取{{ function_name }}导入模板",
description="获取{{ function_name }}导入模板",
dependencies=[Depends(AuthPermission(["{{ permission_prefix }}:download"]))]
"/import",
summary="导入{{ function_name }}",
response_model=ResponseSchema[str],
)
async def export_{{ business_name_slug }}_template_controller() -> StreamingResponse:
async def import_obj_list_controller(
file: UploadFile,
auth: Annotated[AuthSchema, Depends(AuthPermission(["{{ permission_prefix }}:import"]))],
) -> JSONResponse:
"""
获取{{ function_name }}导入模板接口
导入{{ function_name }}
参数:
- file (UploadFile): 导入的Excel文件
- auth (AuthSchema): 认证信息模型
返回:
- StreamingResponse - 包含{{ function_name }}导入模板的流式响应
- JSONResponse: 包含导入{{ function_name }}详情的JSON响应
"""
import_template_result = await {{ class_name }}Service.import_template_download_{{ business_name_slug }}_service()
log.info('获取{{ function_name }}导入模板成功')
batch_import_result = await {{ class_name }}Service.batch_import_service(
file=file, auth=auth, update_support=True
)
return SuccessResponse(data=batch_import_result, msg="导入{{ function_name }}成功")
@{{ class_name }}Router.post(
"/download/template",
summary="获取{{ function_name }}导入模板",
dependencies=[Depends(AuthPermission(["{{ permission_prefix }}:download"]))],
)
async def export_obj_template_controller() -> StreamingResponse:
"""
获取{{ function_name }}导入模板
返回:
- StreamingResponse: 包含{{ function_name }}导入模板的Excel文件流响应
"""
import_template_result = await {{ class_name }}Service.import_template_download_service()
return StreamResponse(
data=bytes2file_response(import_template_result),
media_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
headers={'Content-Disposition': 'attachment; filename={{ table_name }}_template.xlsx'}
media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
headers={
"Content-Disposition": f"attachment; filename={urllib.parse.quote('{{ function_name }}导入模板.xlsx')}",
"Access-Control-Expose-Headers": "Content-Disposition",
},
)
@@ -1,11 +1,9 @@
# -*- coding: utf-8 -*-
from typing import Sequence
from app.core.base_crud import CRUDBase
from app.api.v1.module_system.auth.schema import AuthSchema
from .model import {{ class_name }}Model
from .schema import {{ class_name }}CreateSchema, {{ class_name }}UpdateSchema, {{ class_name }}OutSchema
from .schema import {{ class_name }}CreateSchema, {{ class_name }}UpdateSchema
class {{ class_name }}CRUD(CRUDBase[{{ class_name }}Model, {{ class_name }}CreateSchema, {{ class_name }}UpdateSchema]):
@@ -14,110 +12,8 @@ class {{ class_name }}CRUD(CRUDBase[{{ class_name }}Model, {{ class_name }}Creat
def __init__(self, auth: AuthSchema) -> None:
"""
初始化CRUD数据层
参数:
- auth (AuthSchema): 认证信息模型
"""
super().__init__(model={{ class_name }}Model, auth=auth)
async def get_by_id_{{ business_name_slug }}_crud(self, id: int, preload: list | None = None) -> {{ class_name }}Model | None:
"""
详情
参数:
- id (int): 对象ID
- preload (list | None): 预加载关系,未提供时使用模型默认项
返回:
- {{ class_name }}Model | None: 模型实例或None
"""
return await self.get(id=id, preload=preload)
async def list_{{ business_name_slug }}_crud(self, search: dict | None = None, order_by: list[dict] | None = None, preload: list | None = None) -> Sequence[{{ class_name }}Model]:
"""
列表查询
参数:
- search (dict | None): 查询参数
- order_by (list[dict] | None): 排序参数,未提供时使用模型默认项
- preload (list | None): 预加载关系,未提供时使用模型默认项
返回:
- Sequence[{{ class_name }}Model]: 模型实例序列
"""
return await self.list(search=search, order_by=order_by, preload=preload)
async def create_{{ business_name_slug }}_crud(self, data: {{ class_name }}CreateSchema) -> {{ class_name }}Model | None:
"""
创建
参数:
- data ({{ class_name }}CreateSchema): 创建模型
返回:
- {{ class_name }}Model | None: 模型实例或None
"""
return await self.create(data=data)
async def update_{{ business_name_slug }}_crud(self, id: int, data: {{ class_name }}UpdateSchema) -> {{ class_name }}Model | None:
"""
更新
参数:
- id (int): 对象ID
- data ({{ class_name }}UpdateSchema): 更新模型
返回:
- {{ class_name }}Model | None: 模型实例或None
"""
return await self.update(id=id, data=data)
async def delete_{{ business_name_slug }}_crud(self, ids: list[int]) -> None:
"""
批量删除
参数:
- ids (list[int]): 对象ID列表
返回:
- None
"""
return await self.delete(ids=ids)
async def set_available_{{ business_name_slug }}_crud(self, ids: list[int], status: str) -> None:
"""
批量设置可用状态
参数:
- ids (list[int]): 对象ID列表
- status (str): 可用状态
返回:
- None
"""
return await self.set(ids=ids, status=status)
async def page_{{ business_name_slug }}_crud(self, offset: int, limit: int, order_by: list[dict] | None = None, search: dict | None = None, preload: list | None = None) -> dict:
"""
分页查询
参数:
- offset (int): 偏移量
- limit (int): 每页数量
- order_by (list[dict] | None): 排序参数,未提供时使用模型默认项
- search (dict | None): 查询参数,未提供时查询所有
- preload (list | None): 预加载关系,未提供时使用模型默认项
返回:
- Dict: 分页数据
"""
order_by_list = order_by or [{'{{ pk_column_name }}': 'asc'}]
search_dict = search or {}
return await self.page(
offset=offset,
limit=limit,
order_by=order_by_list,
search=search_dict,
out_schema={{ class_name }}OutSchema,
preload=preload
)
@@ -7,7 +7,6 @@ from fastapi import UploadFile
from app.api.v1.module_system.auth.schema import AuthSchema
from app.core.base_schema import BatchSetAvailable
from app.core.exceptions import CustomException
from app.core.logger import log
from app.utils.excel_util import ExcelUtil
from .crud import {{ class_name }}CRUD
@@ -18,166 +17,166 @@ from .schema import (
{{ class_name }}QueryParam
)
class {{ class_name }}Service:
"""
{{ function_name }}服务层
"""
@classmethod
async def detail_{{ business_name_slug }}_service(cls, auth: AuthSchema, id: int) -> dict:
"""
详情
参数:
- auth: AuthSchema - 认证信息
- id: int - 数据ID
返回:
- dict - 数据详情
"""
obj = await {{ class_name }}CRUD(auth).get_by_id_{{ business_name_slug }}_crud(id=id)
obj = await {{ class_name }}CRUD(auth).get(id=id)
if not obj:
raise CustomException(msg="该数据不存在")
return {{ class_name }}OutSchema.model_validate(obj).model_dump()
@classmethod
async def list_{{ business_name_slug }}_service(cls, auth: AuthSchema, search: {{ class_name }}QueryParam | None = None, order_by: list[dict] | None = None) -> list[dict]:
"""
列表查询
参数:
- auth: AuthSchema - 认证信息
- search: {{ class_name }}QueryParam | None - 查询参数
- order_by: list[dict] | None - 排序参数
返回:
- list[dict] - 数据列表
"""
search_dict = search.__dict__ if search else None
obj_list = await {{ class_name }}CRUD(auth).list_{{ business_name_slug }}_crud(search=search_dict, order_by=order_by)
obj_list = await {{ class_name }}CRUD(auth).list(search=search_dict, order_by=order_by)
return [{{ class_name }}OutSchema.model_validate(obj).model_dump() for obj in obj_list]
@classmethod
async def page_{{ business_name_slug }}_service(cls, auth: AuthSchema, page_no: int, page_size: int, search: {{ class_name }}QueryParam | None = None, order_by: list[dict] | None = None) -> dict:
"""
分页查询(数据库分页)
参数:
- auth: AuthSchema - 认证信息
- page_no: int - 页码
- page_size: int - 每页数量
- search: {{ class_name }}QueryParam | None - 查询参数
- order_by: list[dict] | None - 排序参数
返回:
- dict - 分页查询结果
"""
search_dict = search.__dict__ if search else {}
order_by_list = order_by or [{'{{ pk_column_name }}': 'asc'}]
offset = (page_no - 1) * page_size
result = await {{ class_name }}CRUD(auth).page_{{ business_name_slug }}_crud(
result = await {{ class_name }}CRUD(auth).page(
offset=offset,
limit=page_size,
order_by=order_by_list,
search=search_dict
search=search_dict,
out_schema={{ class_name }}OutSchema
)
return result
@classmethod
async def create_{{ business_name_slug }}_service(cls, auth: AuthSchema, data: {{ class_name }}CreateSchema) -> dict:
"""
创建
参数:
- auth: AuthSchema - 认证信息
- data: {{ class_name }}CreateSchema - 创建数据
返回:
- dict - 创建结果
"""
{% for column in columns %}
{% if column.is_unique == '1' %}
{% if column.is_unique %}
obj = await {{ class_name }}CRUD(auth).get({{ column.column_name }}=data.{{ column.column_name }})
if obj:
raise CustomException(msg='创建失败,{{ column.column_comment }}已存在')
{% endif %}
{% endfor %}
obj = await {{ class_name }}CRUD(auth).create_{{ business_name_slug }}_crud(data=data)
obj = await {{ class_name }}CRUD(auth).create(data=data)
return {{ class_name }}OutSchema.model_validate(obj).model_dump()
@classmethod
async def update_{{ business_name_slug }}_service(cls, auth: AuthSchema, id: int, data: {{ class_name }}UpdateSchema) -> dict:
"""
更新
参数:
- auth: AuthSchema - 认证信息
- id: int - 数据ID
- data: {{ class_name }}UpdateSchema - 更新数据
返回:
- dict - 更新结果
"""
# 检查数据是否存在
obj = await {{ class_name }}CRUD(auth).get_by_id_{{ business_name_slug }}_crud(id=id)
obj = await {{ class_name }}CRUD(auth).get(id=id)
if not obj:
raise CustomException(msg='更新失败,该数据不存在')
# 检查唯一性约束
{% for column in columns %}
{% if column.is_unique == '1' %}
{% if column.is_unique %}
exist_obj = await {{ class_name }}CRUD(auth).get({{ column.column_name }}=data.{{ column.column_name }})
if exist_obj and getattr(exist_obj, '{{ pk_column_name }}') != id:
raise CustomException(msg='更新失败,{{ column.column_comment }}重复')
{% endif %}
{% endfor %}
obj = await {{ class_name }}CRUD(auth).update_{{ business_name_slug }}_crud(id=id, data=data)
obj = await {{ class_name }}CRUD(auth).update(id=id, data=data)
return {{ class_name }}OutSchema.model_validate(obj).model_dump()
@classmethod
async def delete_{{ business_name_slug }}_service(cls, auth: AuthSchema, ids: list[int]) -> None:
"""
删除
参数:
- auth: AuthSchema - 认证信息
- ids: list[int] - 数据ID列表
返回:
- None
"""
if len(ids) < 1:
raise CustomException(msg='删除失败,删除对象不能为空')
for id in ids:
obj = await {{ class_name }}CRUD(auth).get_by_id_{{ business_name_slug }}_crud(id=id)
obj = await {{ class_name }}CRUD(auth).get(id=id)
if not obj:
raise CustomException(msg=f'删除失败,ID为{id}的数据不存在')
await {{ class_name }}CRUD(auth).delete_{{ business_name_slug }}_crud(ids=ids)
await {{ class_name }}CRUD(auth).delete(ids=ids)
@classmethod
async def set_available_{{ business_name_slug }}_service(cls, auth: AuthSchema, data: BatchSetAvailable) -> None:
"""
批量设置状态
参数:
- auth: AuthSchema - 认证信息
- data: BatchSetAvailable - 批量设置状态数据
返回:
- None
"""
await {{ class_name }}CRUD(auth).set_available_{{ business_name_slug }}_crud(ids=data.ids, status=data.status)
await {{ class_name }}CRUD(auth).set(ids=data.ids, status=data.status)
@classmethod
async def batch_export_{{ business_name_slug }}_service(cls, obj_list: list[dict]) -> bytes:
"""
批量导出
参数:
- obj_list: list[dict] - 数据列表
返回:
- bytes - 导出的Excel文件内容
"""
@@ -190,7 +189,7 @@ class {{ class_name }}Service:
data = obj_list.copy()
for item in data:
# 处理状态
item["status"] = "启用" if item.get("status") == "0" else "停用"
item["status"] = "启用" if item.get("status") == 0 else "停用"
# 处理创建者
creator_info = item.get("created_id")
if isinstance(creator_info, dict):
@@ -204,12 +203,12 @@ class {{ class_name }}Service:
async def batch_import_{{ business_name_slug }}_service(cls, auth: AuthSchema, file: UploadFile, update_support: bool = False) -> str:
"""
批量导入
参数:
- auth: AuthSchema - 认证信息
- file: UploadFile - 上传的Excel文件
- update_support: bool - 是否支持更新存在数据
返回:
- str - 导入结果信息
"""
@@ -235,25 +234,25 @@ class {{ class_name }}Service:
# 重命名列名
df.rename(columns=header_dict, inplace=True)
# 验证必填字段
# 验证必填字段(非主键且不允许为空的列)
{% for column in columns %}
{% if column.required == '1' %}
{% if column.is_nullable is false and column.is_pk is false %}
errors = []
missing_rows = df[df['{{ column.column_name }}'].isnull()].index.tolist()
if missing_rows:
field_name = [k for k,v in header_dict.items() if v == field][0]
field_name = [k for k,v in header_dict.items() if v == '{{ column.column_name }}'][0]
rows_str = "、".join([str(i+1) for i in missing_rows])
errors.append(f"{field_name}不能为空,第{rows_str}行")
if errors:
raise CustomException(msg=f"导入失败,以下行缺少必要字段:\n{'; '.join(errors)}")
{% endif %}
{% endfor %}
error_msgs = []
success_count = 0
count = 0
for _index, row in df.iterrows():
count += 1
try:
@@ -264,10 +263,10 @@ class {{ class_name }}Service:
}
# 使用CreateSchema做校验后入库
create_schema = {{ class_name }}CreateSchema.model_validate(data)
# 检查唯一性约束
{% for column in columns %}
{% if column.is_unique == '1' %}
{% if column.is_unique %}
exists_obj = await {{ class_name }}CRUD(auth).get({{ column.column_name }}=create_schema.{{ column.column_name }})
if exists_obj:
if update_support:
@@ -278,8 +277,8 @@ class {{ class_name }}Service:
continue
{% endif %}
{% endfor %}
await {{ class_name }}CRUD(auth).create_{{ business_name_slug }}_crud(data=create_schema)
await {{ class_name }}CRUD(auth).create(data=create_schema)
success_count += 1
except Exception as e:
error_msgs.append(f"第{count}行: {str(e)}")
@@ -289,16 +288,16 @@ class {{ class_name }}Service:
if error_msgs:
result += "\n错误信息:\n" + "\n".join(error_msgs)
return result
except Exception as e:
log.error(f"批量导入失败: {str(e)}")
logger.error(f"批量导入失败: {str(e)}")
raise CustomException(msg=f"导入失败: {str(e)}")
@classmethod
async def import_template_download_{{ business_name_slug }}_service(cls) -> bytes:
"""
下载导入模板
返回:
- bytes - Excel文件的二进制数据
"""
@@ -309,16 +308,16 @@ class {{ class_name }}Service:
]
selector_header_list = []
option_list = []
{% for column in columns %}
{% if column.html_type == 'select' and column.dict_type %}
selector_header_list.append('{{ column.column_comment }}')
option_list.append({'{{ column.column_comment }}': []})
{% endif %}
{% endfor %}
return ExcelUtil.get_excel_template(
header_list=header_list,
selector_header_list=selector_header_list,
option_list=option_list
)
)