mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-10-02 00:27:16 +00:00
fix(module_generator): 修复代码生成器关键问题及模板路径错误
- 修正 CRUD 基类初始化时 model 参数传递方式,改为实例化对象 - 修改部分查询中条件字段名的错误,table_id 改为 id - 修正数据库方言下查询语句缺少 SELECT 关键字的问题 - 优化查询参数绑定,避免直接传递包含分页参数的字典 - 修正生成表结构后返回数据中的主键字段 id 替代 table_id - 优化删除逻辑中获取列 ID 的字段名称错误 - 重写建表功能相关代码,添加异常捕获和事务回滚 - 取消子表字段 Schema 的非空强制,改为可选类型 - 修正前端接口请求路径及参数命名,使其更加直观和规范 - 修改模板加载路径为绝对路径,确保多环境下模板加载正确 - 修复模板工具中子表相关属性为空时的类型检查错误 - 调整模板文件及路径后缀名,统一从 .jinja2 改为 .j2 - 修正生成文件路径映射以符合新模板路径和文件名规范 - 删除冗余和废弃的 Python 控制器及 CRUD 模板文件 - 修正 SQL 菜单模板中模块名路径格式错误 - 更新前端 Vue API 调用函数参数与接口路径一致性
This commit is contained in:
@@ -27,7 +27,7 @@ class GenTableDao(CRUDBase[GenTableModel, GenTableBaseSchema, GenTableBaseSchema
|
|||||||
|
|
||||||
def __init__(self, auth: AuthSchema) -> None:
|
def __init__(self, auth: AuthSchema) -> None:
|
||||||
"""初始化CRUD"""
|
"""初始化CRUD"""
|
||||||
super().__init__(model=GenTableModel, auth=auth)
|
super().__init__(model=GenTableModel(), auth=auth)
|
||||||
|
|
||||||
async def get_gen_table_by_id(self, db: AsyncSession, table_id: int) -> Optional[GenTableModel]:
|
async def get_gen_table_by_id(self, db: AsyncSession, table_id: int) -> Optional[GenTableModel]:
|
||||||
"""
|
"""
|
||||||
@@ -40,7 +40,7 @@ class GenTableDao(CRUDBase[GenTableModel, GenTableBaseSchema, GenTableBaseSchema
|
|||||||
gen_table_info = (
|
gen_table_info = (
|
||||||
(
|
(
|
||||||
await db.execute(
|
await db.execute(
|
||||||
select(GenTableModel).options(selectinload(GenTableModel.columns)).where(GenTableModel.table_id == table_id)
|
select(GenTableModel).options(selectinload(GenTableModel.columns)).where(GenTableModel.id == table_id)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.scalars()
|
.scalars()
|
||||||
@@ -156,7 +156,7 @@ class GenTableDao(CRUDBase[GenTableModel, GenTableBaseSchema, GenTableBaseSchema
|
|||||||
"""
|
"""
|
||||||
if settings.DATABASE_TYPE == 'postgresql':
|
if settings.DATABASE_TYPE == 'postgresql':
|
||||||
query_sql = """
|
query_sql = """
|
||||||
table_name as table_name,
|
SELECT table_name as table_name,
|
||||||
table_comment as table_comment,
|
table_comment as table_comment,
|
||||||
create_time as create_time,
|
create_time as create_time,
|
||||||
update_time as update_time
|
update_time as update_time
|
||||||
@@ -169,7 +169,7 @@ class GenTableDao(CRUDBase[GenTableModel, GenTableBaseSchema, GenTableBaseSchema
|
|||||||
"""
|
"""
|
||||||
else:
|
else:
|
||||||
query_sql = """
|
query_sql = """
|
||||||
table_name as table_name,
|
SELECT table_name as table_name,
|
||||||
table_comment as table_comment,
|
table_comment as table_comment,
|
||||||
create_time as create_time,
|
create_time as create_time,
|
||||||
update_time as update_time
|
update_time as update_time
|
||||||
@@ -185,22 +185,16 @@ class GenTableDao(CRUDBase[GenTableModel, GenTableBaseSchema, GenTableBaseSchema
|
|||||||
query_sql += """and lower(table_name) like lower(concat('%', :table_name, '%'))"""
|
query_sql += """and lower(table_name) like lower(concat('%', :table_name, '%'))"""
|
||||||
if query_object.table_comment:
|
if query_object.table_comment:
|
||||||
query_sql += """and lower(table_comment) like lower(concat('%', :table_comment, '%'))"""
|
query_sql += """and lower(table_comment) like lower(concat('%', :table_comment, '%'))"""
|
||||||
if hasattr(query_object, 'created_at') and query_object.created_at:
|
# 修复查询参数处理
|
||||||
if isinstance(query_object.created_at, tuple) and query_object.created_at[0] == "between":
|
query_params = {
|
||||||
# 这里需要特殊处理时间范围查询
|
k: v for k, v in query_object.model_dump(exclude_none=True, exclude={'page_no', 'page_size'}).items()
|
||||||
pass
|
}
|
||||||
|
|
||||||
query_sql += """order by create_time desc"""
|
query_sql += """order by create_time desc"""
|
||||||
query = select(
|
query = text(query_sql).bindparams(**query_params)
|
||||||
text(query_sql).bindparams(
|
|
||||||
**{
|
|
||||||
k: v
|
|
||||||
for k, v in query_object.model_dump(exclude_none=True, exclude={'page_no', 'page_size'}).items()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# 执行查询
|
# 执行查询
|
||||||
result = await db.execute(query)
|
result = await db.execute(select(query))
|
||||||
all_data = list(result.fetchall())
|
all_data = list(result.fetchall())
|
||||||
|
|
||||||
# 使用PaginationService.paginate进行分页
|
# 使用PaginationService.paginate进行分页
|
||||||
@@ -270,7 +264,7 @@ class GenTableColumnDao(CRUDBase[GenTableColumnModel, GenTableColumnBaseSchema,
|
|||||||
|
|
||||||
def __init__(self, auth: AuthSchema) -> None:
|
def __init__(self, auth: AuthSchema) -> None:
|
||||||
"""初始化CRUD"""
|
"""初始化CRUD"""
|
||||||
super().__init__(model=GenTableColumnModel, auth=auth)
|
super().__init__(model=GenTableColumnModel(), auth=auth)
|
||||||
|
|
||||||
async def get_gen_table_column_list_by_table_id(self, db: AsyncSession, table_id: int) -> Sequence[GenTableColumnModel]:
|
async def get_gen_table_column_list_by_table_id(self, db: AsyncSession, table_id: int) -> Sequence[GenTableColumnModel]:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ from typing import Optional
|
|||||||
from fastapi import Query
|
from fastapi import Query
|
||||||
|
|
||||||
from app.core.validator import DateTimeStr
|
from app.core.validator import DateTimeStr
|
||||||
from app.common.request import PageResultSchema
|
from app.core.base_params import PaginationQueryParam
|
||||||
from .schema import GenTableBaseSchema, GenTableColumnBaseSchema
|
from .schema import GenTableBaseSchema, GenTableColumnBaseSchema
|
||||||
|
|
||||||
|
|
||||||
class GenTableQueryParam(PageResultSchema, GenTableBaseSchema):
|
class GenTableQueryParam(PaginationQueryParam, GenTableBaseSchema):
|
||||||
"""数据库表查询参数"""
|
"""数据库表查询参数"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -36,7 +36,7 @@ class GenTableQueryParam(PageResultSchema, GenTableBaseSchema):
|
|||||||
self.created_at = ("between", (start_datetime, end_datetime))
|
self.created_at = ("between", (start_datetime, end_datetime))
|
||||||
|
|
||||||
|
|
||||||
class GenTableColumnQueryParam(PageResultSchema, GenTableColumnBaseSchema):
|
class GenTableColumnQueryParam(PaginationQueryParam, GenTableColumnBaseSchema):
|
||||||
"""数据库表字段查询参数"""
|
"""数据库表字段查询参数"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -61,4 +61,3 @@ class GenTableColumnQueryParam(PageResultSchema, GenTableColumnBaseSchema):
|
|||||||
start_datetime = datetime.strptime(str(start_time), '%Y-%m-%d %H:%M:%S')
|
start_datetime = datetime.strptime(str(start_time), '%Y-%m-%d %H:%M:%S')
|
||||||
end_datetime = datetime.strptime(str(end_time), '%Y-%m-%d %H:%M:%S')
|
end_datetime = datetime.strptime(str(end_time), '%Y-%m-%d %H:%M:%S')
|
||||||
self.created_at = ("between", (start_datetime, end_datetime))
|
self.created_at = ("between", (start_datetime, end_datetime))
|
||||||
|
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ class GenTableSchema(GenTableBaseSchema):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
pk_column: Optional['GenTableColumnSchema'] = Field(default=None, description='主键信息')
|
pk_column: Optional['GenTableColumnSchema'] = Field(default=None, description='主键信息')
|
||||||
sub_table: 'GenTableSchema' = Field(default=..., description='子表信息')
|
sub_table: Optional['GenTableSchema'] = Field(default=None, description='子表信息')
|
||||||
columns: List['GenTableColumnSchema'] = Field(default=..., description='表列信息')
|
columns: List['GenTableColumnSchema'] = Field(default=..., description='表列信息')
|
||||||
tree_code: Optional[str] = Field(default=None, description='树编码字段')
|
tree_code: Optional[str] = Field(default=None, description='树编码字段')
|
||||||
tree_parent_code: Optional[str] = Field(default=None, description='树父编码字段')
|
tree_parent_code: Optional[str] = Field(default=None, description='树父编码字段')
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
|||||||
from typing import Any, List, Dict, Optional, Sequence
|
from typing import Any, List, Dict, Optional, Sequence
|
||||||
|
|
||||||
from app.config.setting import settings
|
from app.config.setting import settings
|
||||||
|
from app.core.base_model import CamelCaseUtil
|
||||||
from app.core.exceptions import CustomException
|
from app.core.exceptions import CustomException
|
||||||
from app.utils.gen_util import GenUtils
|
from app.utils.gen_util import GenUtils
|
||||||
from app.utils.template_util import TemplateInitializer, TemplateUtils
|
from app.utils.template_util import TemplateInitializer, TemplateUtils
|
||||||
@@ -116,7 +117,7 @@ class GenTableService:
|
|||||||
GenUtils.init_table(table, current_user.username) # 使用username而不是user.user_name
|
GenUtils.init_table(table, current_user.username) # 使用username而不是user.user_name
|
||||||
add_gen_table = await gen_table_dao.create(data=table.model_dump())
|
add_gen_table = await gen_table_dao.create(data=table.model_dump())
|
||||||
if add_gen_table:
|
if add_gen_table:
|
||||||
table.table_id = add_gen_table.table_id
|
table.table_id = add_gen_table.id
|
||||||
gen_table_columns = await gen_table_column_dao.get_gen_db_table_columns_by_name(auth.db, table_name or "")
|
gen_table_columns = await gen_table_column_dao.get_gen_db_table_columns_by_name(auth.db, table_name or "")
|
||||||
for column in [
|
for column in [
|
||||||
GenTableColumnSchema(**gen_table_column)
|
GenTableColumnSchema(**gen_table_column)
|
||||||
@@ -217,7 +218,7 @@ class GenTableService:
|
|||||||
# 这里需要先查询出所有相关的column_id,然后删除
|
# 这里需要先查询出所有相关的column_id,然后删除
|
||||||
columns = await gen_table_column_dao.get_gen_table_column_list_by_table_id(auth.db, int(table_id))
|
columns = await gen_table_column_dao.get_gen_table_column_list_by_table_id(auth.db, int(table_id))
|
||||||
if columns:
|
if columns:
|
||||||
column_ids = [column.column_id for column in columns]
|
column_ids = [column.id for column in columns]
|
||||||
await gen_table_column_dao.delete(ids=column_ids)
|
await gen_table_column_dao.delete(ids=column_ids)
|
||||||
if isinstance(auth.db, AsyncSession):
|
if isinstance(auth.db, AsyncSession):
|
||||||
await auth.db.commit()
|
await auth.db.commit()
|
||||||
@@ -281,8 +282,25 @@ class GenTableService:
|
|||||||
:param current_user: 当前用户信息对象
|
:param current_user: 当前用户信息对象
|
||||||
:return: 创建表结构结果
|
:return: 创建表结构结果
|
||||||
"""
|
"""
|
||||||
# 移除sqlglot相关代码,因为导入失败
|
# 确保db是AsyncSession类型
|
||||||
raise CustomException(msg='建表功能暂不可用')
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
gen_table_dao = GenTableDao(auth=auth)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 执行SQL语句创建表
|
||||||
|
await gen_table_dao.create_table_by_sql_dao(auth.db, [sql])
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
await auth.db.commit()
|
||||||
|
return SuccessResponse(msg='创建表结构成功')
|
||||||
|
except Exception as e:
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
try:
|
||||||
|
await auth.db.rollback()
|
||||||
|
except:
|
||||||
|
pass # 忽略回滚错误
|
||||||
|
raise CustomException(msg=f'创建表结构失败: {str(e)}')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def preview_code_services(cls, auth: AuthSchema, table_id: int) -> dict[Any, Any]:
|
async def preview_code_services(cls, auth: AuthSchema, table_id: int) -> dict[Any, Any]:
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from fastapi import APIRouter, Depends, Form
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from starlette.requests import Request
|
||||||
|
from typing import List
|
||||||
|
from app.common.enums import BusinessType
|
||||||
|
from app.core.dependencies import get_db
|
||||||
|
from app.common.response import SuccessResponse
|
||||||
|
from app.core.dependencies import AuthPermission
|
||||||
|
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||||
|
from app.api.v1.module_system.user.schema import UserOutSchema
|
||||||
|
from app.utils.common_util import bytes2file_response
|
||||||
|
|
||||||
|
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
from {{ packageName }}.service.{{ tableName }}_service import {{ tableName|snake_to_pascal_case }}Service
|
||||||
|
|
||||||
|
{{ tableName|snake_to_camel }}Controller = APIRouter(prefix='/{{ moduleName }}/{{ businessName }}', tags=["{{ functionName }}模块"])
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.get('/list', summary="查询{{ functionName }}列表", description="查询{{ functionName }}列表")
|
||||||
|
async def get_{{ tableName }}_list(
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:list"])),
|
||||||
|
page_query: {{ tableName|snake_to_pascal_case }}PageModel = Depends({{ tableName|snake_to_pascal_case }}PageModel.as_query)
|
||||||
|
):
|
||||||
|
{{ tableName }}_result = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_list_services(auth, page_query)
|
||||||
|
|
||||||
|
return SuccessResponse(data={{ tableName }}_result)
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.get('/{id}', summary="获取{{ functionName }}详细信息", description="获取{{ functionName }}详细信息")
|
||||||
|
async def get_{{ tableName }}_by_id(
|
||||||
|
id: int,
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:query"]))
|
||||||
|
):
|
||||||
|
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_by_id_services(auth, id)
|
||||||
|
return SuccessResponse(data={{ tableName }})
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.post('', summary="新增{{ functionName }}", description="新增{{ functionName }}")
|
||||||
|
async def add_{{ tableName }} (
|
||||||
|
add_model: {{ tableName|snake_to_pascal_case }}Model,
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:add"])),
|
||||||
|
current_user: UserOutSchema = Depends(lambda auth: auth.user)
|
||||||
|
):
|
||||||
|
add_model.create_by = current_user.username
|
||||||
|
add_result = await {{ tableName|snake_to_pascal_case }}Service.add_{{ tableName }}_services(auth, add_model)
|
||||||
|
return SuccessResponse(msg="新增成功")
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.put('', summary="修改{{ functionName }}", description="修改{{ functionName }}")
|
||||||
|
async def update_{{ tableName }}(
|
||||||
|
edit_model: {{ tableName|snake_to_pascal_case }}Model,
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:edit"])),
|
||||||
|
current_user: UserOutSchema = Depends(lambda auth: auth.user)
|
||||||
|
):
|
||||||
|
edit_model.update_by = current_user.username
|
||||||
|
update_result = await {{ tableName|snake_to_pascal_case }}Service.update_{{ tableName }}_services(auth, edit_model)
|
||||||
|
return SuccessResponse(msg="修改成功")
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.delete('/{ids}', summary="删除{{ functionName }}", description="删除{{ functionName }}")
|
||||||
|
async def del_{{ tableName }}(
|
||||||
|
ids: str,
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:remove"]))
|
||||||
|
):
|
||||||
|
id_list = ids.split(',')
|
||||||
|
del_result = await {{ tableName|snake_to_pascal_case }}Service.del_{{ tableName }}_services(auth, id_list)
|
||||||
|
return SuccessResponse(msg="删除成功")
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.post('/export', summary="导出{{ functionName }}", description="导出{{ functionName }}")
|
||||||
|
async def export_{{ tableName }}(
|
||||||
|
{{ tableName }}_form: {{ tableName|snake_to_pascal_case }}PageModel = Form(),
|
||||||
|
auth: AuthSchema = Depends(AuthPermission(permissions=["{{ permissionPrefix }}:export"]))
|
||||||
|
):
|
||||||
|
# 获取全量数据
|
||||||
|
export_result = await {{ tableName|snake_to_pascal_case }}Service.export_{{ tableName }}_list_services(
|
||||||
|
auth, {{ tableName }}_form
|
||||||
|
)
|
||||||
|
return bytes2file_response(export_result)
|
||||||
|
|
||||||
|
|
||||||
|
@{{ tableName|snake_to_camel }}Controller.post('/import', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:import'))])
|
||||||
|
async def import_{{ tableName }}(request: Request,
|
||||||
|
import_model: ImportModel,
|
||||||
|
query_db: AsyncSession = Depends(get_db),
|
||||||
|
current_user: CurrentUserModel = Depends(LoginService.get_current_user)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
导入数据
|
||||||
|
"""
|
||||||
|
await ImportService.import_data(query_db, import_model, current_user)
|
||||||
|
return ResponseUtil.success()
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
# -*- coding:utf-8 -*-
|
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, Form
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
from starlette.requests import Request
|
|
||||||
from typing import List
|
|
||||||
from config.enums import BusinessType
|
|
||||||
from config.get_db import get_db
|
|
||||||
from module_admin.entity.vo.import_vo import ImportModel
|
|
||||||
from module_admin.service.import_service import ImportService
|
|
||||||
from module_admin.service.login_service import LoginService
|
|
||||||
from module_admin.aspect.data_scope import GetDataScope
|
|
||||||
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
|
|
||||||
from module_admin.entity.vo.user_vo import CurrentUserModel
|
|
||||||
from module_admin.annotation.log_annotation import Log
|
|
||||||
from utils.response_util import ResponseUtil
|
|
||||||
from utils.common_util import bytes2file_response
|
|
||||||
|
|
||||||
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
|
||||||
from {{ packageName }}.service.{{ tableName }}_service import {{ tableName|snake_to_pascal_case }}Service
|
|
||||||
|
|
||||||
{{ tableName|snake_to_camel }}Controller = APIRouter(prefix='/{{ moduleName }}/{{ businessName }}', dependencies=[Depends(LoginService.get_current_user)])
|
|
||||||
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.get('/list', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:query'))])
|
|
||||||
async def get_{{ tableName }}_list(
|
|
||||||
request: Request,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
page_query: {{ tableName|snake_to_pascal_case }}PageModel = Depends( {{ tableName|snake_to_pascal_case }}PageModel.as_query),
|
|
||||||
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}'))
|
|
||||||
):
|
|
||||||
{{ tableName }}_result = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_list(query_db, page_query, data_scope_sql)
|
|
||||||
|
|
||||||
return ResponseUtil.success(model_content={{ tableName }}_result)
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.get('/getById/{{ '{' }}{{ tableName|snake_to_camel }}Id{{ '}' }}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:query'))])
|
|
||||||
async def get_{{ tableName }}_by_id(
|
|
||||||
request: Request,
|
|
||||||
{{ tableName|snake_to_camel }}Id: int,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}'))
|
|
||||||
):
|
|
||||||
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Service.get_{{ tableName }}_by_id(query_db, {{ tableName|snake_to_camel }}Id)
|
|
||||||
return ResponseUtil.success(data={{ tableName }})
|
|
||||||
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.post('/add', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:add'))])
|
|
||||||
@Log(title='{{ tableName }}', business_type=BusinessType.INSERT)
|
|
||||||
async def add_{{ tableName }} (
|
|
||||||
request: Request,
|
|
||||||
add_model: {{ tableName|snake_to_pascal_case }}Model,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
):
|
|
||||||
|
|
||||||
add_model.create_by = current_user.user.user_id
|
|
||||||
add_model.dept_id = current_user.user.dept_id
|
|
||||||
add_dict_type_result = await {{ tableName|snake_to_pascal_case }}Service.add_{{ tableName }}(query_db, add_model)
|
|
||||||
return ResponseUtil.success(data=add_dict_type_result)
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.put('/update', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:edit'))])
|
|
||||||
@Log(title='{{ tableName }}', business_type=BusinessType.UPDATE)
|
|
||||||
async def update_{{ tableName }}(
|
|
||||||
request: Request,
|
|
||||||
edit_model: {{ tableName|snake_to_pascal_case }}Model,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
):
|
|
||||||
add_dict_type_result = await {{ tableName|snake_to_pascal_case }}Service.update_{{ tableName }}(query_db, edit_model)
|
|
||||||
return ResponseUtil.success(data=add_dict_type_result)
|
|
||||||
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.delete('/delete/{{ '{' }}{{ tableName|snake_to_camel }}Ids{{ '}' }}', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:remove'))])
|
|
||||||
@Log(title='{{ tableName }}', business_type=BusinessType.DELETE)
|
|
||||||
async def del_{{ tableName }}(
|
|
||||||
request: Request,
|
|
||||||
{{ tableName|snake_to_camel }}Ids: str,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
|
|
||||||
):
|
|
||||||
ids = {{ tableName|snake_to_camel }}Ids.split(',')
|
|
||||||
del_result = await {{ tableName|snake_to_pascal_case }}Service.del_{{ tableName }}(query_db, ids)
|
|
||||||
return ResponseUtil.success(data=del_result)
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.post('/export', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:export'))])
|
|
||||||
@Log(title='{{ tableName }}', business_type=BusinessType.EXPORT)
|
|
||||||
async def export_{{ tableName }}(
|
|
||||||
request: Request,
|
|
||||||
{{ tableName }}_form: {{ tableName|snake_to_pascal_case }}PageModel = Form(),
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
data_scope_sql: str = Depends(GetDataScope('{{ tableName|snake_to_pascal_case }}')),
|
|
||||||
):
|
|
||||||
# 获取全量数据
|
|
||||||
export_result = await {{ tableName|snake_to_pascal_case }}Service.export_{{ tableName }}_list(
|
|
||||||
query_db, {{ tableName }}_form, data_scope_sql
|
|
||||||
)
|
|
||||||
return ResponseUtil.streaming(data=bytes2file_response(export_result))
|
|
||||||
|
|
||||||
@{{ tableName|snake_to_camel }}Controller.post('/import', dependencies=[Depends(CheckUserInterfaceAuth('{{ permissionPrefix }}:import'))])
|
|
||||||
async def import_{{ tableName }}(request: Request,
|
|
||||||
import_model: ImportModel,
|
|
||||||
query_db: AsyncSession = Depends(get_db),
|
|
||||||
current_user: CurrentUserModel = Depends(LoginService.get_current_user)
|
|
||||||
):
|
|
||||||
"""
|
|
||||||
导入数据
|
|
||||||
"""
|
|
||||||
await ImportService.import_data(query_db, import_model, current_user)
|
|
||||||
return ResponseUtil.success()
|
|
||||||
+73
@@ -1,5 +1,15 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from typing import List, Optional
|
||||||
|
from sqlalchemy import delete, func, select, update
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from sqlalchemy.orm import selectinload
|
||||||
|
from {{ packageName }}.entity.do.{{ tableName }}_do import {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
from app.core.base_crud import CRUDBase
|
||||||
|
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
from datetime import datetime, time
|
from datetime import datetime, time
|
||||||
from module_admin.entity.do.role_do import SysRoleDept
|
from module_admin.entity.do.role_do import SysRoleDept
|
||||||
@@ -110,3 +120,66 @@ class {{ tableName|snake_to_pascal_case }}CRUD:
|
|||||||
await db.flush()
|
await db.flush()
|
||||||
if auto_commit:
|
if auto_commit:
|
||||||
await db.commit()
|
await db.commit()
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}Dao(CRUDBase[{{ tableName|snake_to_pascal_case }}Model, {{ tableName|snake_to_pascal_case }}Model, {{ tableName|snake_to_pascal_case }}Model]):
|
||||||
|
"""
|
||||||
|
{{ functionName }}模块数据库操作层
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, auth: AuthSchema) -> None:
|
||||||
|
"""初始化CRUD"""
|
||||||
|
super().__init__(model={{ tableName|snake_to_pascal_case }}Model(), auth=auth)
|
||||||
|
|
||||||
|
async def get_{{ tableName }}_by_id(self, db: AsyncSession, {{ tableName }}_id: int) -> Optional[{{ tableName|snake_to_pascal_case }}Model]:
|
||||||
|
"""
|
||||||
|
根据{{ tableName }}id获取{{ functionName }}信息
|
||||||
|
|
||||||
|
:param db: orm对象
|
||||||
|
:param {{ tableName }}_id: {{ tableName }}id
|
||||||
|
:return: {{ functionName }}信息对象
|
||||||
|
"""
|
||||||
|
{{ tableName }}_info = (
|
||||||
|
(
|
||||||
|
await db.execute(
|
||||||
|
select({{ tableName|snake_to_pascal_case }}Model)
|
||||||
|
.where({{ tableName|snake_to_pascal_case }}Model.id == {{ tableName }}_id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.scalars()
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
|
||||||
|
return {{ tableName }}_info
|
||||||
|
|
||||||
|
async def get_{{ tableName }}_list(self, db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, is_page: bool = False):
|
||||||
|
"""
|
||||||
|
根据查询参数获取{{ functionName }}列表信息
|
||||||
|
|
||||||
|
:param db: orm对象
|
||||||
|
:param query_object: 查询参数对象
|
||||||
|
:param is_page: 是否开启分页
|
||||||
|
:return: {{ functionName }}列表信息对象
|
||||||
|
"""
|
||||||
|
query = select({{ tableName|snake_to_pascal_case }}Model)
|
||||||
|
|
||||||
|
# 执行查询
|
||||||
|
result = await db.execute(query)
|
||||||
|
all_data = list(result.scalars().all())
|
||||||
|
|
||||||
|
# 使用PaginationService.paginate进行分页
|
||||||
|
if is_page:
|
||||||
|
paginated_result = await PaginationService.paginate(
|
||||||
|
data_list=all_data,
|
||||||
|
page_no=query_object.page_no,
|
||||||
|
page_size=query_object.page_size
|
||||||
|
)
|
||||||
|
return paginated_result
|
||||||
|
else:
|
||||||
|
return {
|
||||||
|
"items": all_data,
|
||||||
|
"total": len(all_data),
|
||||||
|
"page_no": None,
|
||||||
|
"page_size": None,
|
||||||
|
"has_next": False
|
||||||
|
}
|
||||||
+26
@@ -1,3 +1,11 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import Optional
|
||||||
|
from sqlalchemy import String, Integer, Text, DateTime
|
||||||
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
|
|
||||||
|
from app.core.base_model import Base
|
||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
from sqlalchemy import Column, ForeignKey, {{ importList }}
|
from sqlalchemy import Column, ForeignKey, {{ importList }}
|
||||||
@@ -39,3 +47,21 @@ class {{ subClassName }}(Base, BaseMixin):
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}Model(Base):
|
||||||
|
"""
|
||||||
|
{{ functionName }}
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = '{{ tableName }}'
|
||||||
|
|
||||||
|
__table_args__ = {'comment': '{{ functionName }}'}
|
||||||
|
|
||||||
|
{% for column in columns %}
|
||||||
|
{{ column.columnName }}: Mapped[Optional[{{ column.pythonType }}]] = mapped_column({{ column.columnType|get_sqlalchemy_type }}, nullable=True, comment='{{ column.columnComment }}')
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"<{{ tableName|snake_to_pascal_case }}Model(id={self.id})>"
|
||||||
+48
@@ -1,4 +1,13 @@
|
|||||||
# -*- coding:utf-8 -*-
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from typing import List, Optional
|
||||||
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
|
from pydantic.alias_generators import to_camel
|
||||||
|
|
||||||
|
from app.core.base_params import PageBaseParam
|
||||||
|
from app.core.base_schema import PageBaseSchema
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from pydantic import BaseModel, ConfigDict, Field
|
from pydantic import BaseModel, ConfigDict, Field
|
||||||
from pydantic.alias_generators import to_camel
|
from pydantic.alias_generators import to_camel
|
||||||
@@ -61,3 +70,42 @@ class {{ subTable.table_name | snake_to_pascal_case }}Schema(BaseModel):
|
|||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}BaseModel(BaseModel):
|
||||||
|
"""
|
||||||
|
{{ functionName }}对应pydantic模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
|
||||||
|
|
||||||
|
{% for column in columns %}
|
||||||
|
{{ column.columnName }}: Optional[{{ column.pythonType }}] = Field(default=None, description='{{ column.columnComment }}')
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}Model({{ tableName|snake_to_pascal_case }}BaseModel):
|
||||||
|
"""
|
||||||
|
{{ functionName }}表模型
|
||||||
|
"""
|
||||||
|
|
||||||
|
id: Optional[int] = Field(default=None, description='编号')
|
||||||
|
create_by: Optional[str] = Field(default=None, description='创建者')
|
||||||
|
create_time: Optional[datetime] = Field(default=None, description='创建时间')
|
||||||
|
update_by: Optional[str] = Field(default=None, description='更新者')
|
||||||
|
update_time: Optional[datetime] = Field(default=None, description='更新时间')
|
||||||
|
remark: Optional[str] = Field(default=None, description='备注')
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}PageModel(PageBaseParam, {{ tableName|snake_to_pascal_case }}BaseModel):
|
||||||
|
"""
|
||||||
|
{{ functionName }}分页查询模型
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}PageObject(PageBaseSchema, {{ tableName|snake_to_pascal_case }}Model):
|
||||||
|
"""
|
||||||
|
{{ functionName }}分页查询结果模型
|
||||||
|
"""
|
||||||
|
pass
|
||||||
@@ -0,0 +1,244 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from typing import Any, List, Dict, Optional
|
||||||
|
|
||||||
|
from app.core.exceptions import CustomException
|
||||||
|
from app.common.response import SuccessResponse
|
||||||
|
from app.api.v1.module_system.user.schema import UserOutSchema
|
||||||
|
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||||
|
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
from {{ packageName }}.dao.{{ tableName }}_dao import {{ tableName|snake_to_pascal_case }}Dao
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}Service:
|
||||||
|
"""
|
||||||
|
{{ functionName }}服务层
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_{{ tableName }}_list_services(
|
||||||
|
cls, auth: AuthSchema, query_object: {{ tableName|snake_to_pascal_case }}PageModel
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
获取{{ functionName }}列表信息service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param query_object: 查询参数对象
|
||||||
|
:return: {{ functionName }}列表信息对象
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
{{ tableName }}_list_result = await {{ tableName }}_dao.get_{{ tableName }}_list(auth.db, query_object, is_page=True)
|
||||||
|
|
||||||
|
return {{ tableName }}_list_result
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_{{ tableName }}_by_id_services(cls, auth: AuthSchema, {{ tableName }}_id: int) -> {{ tableName|snake_to_pascal_case }}Model:
|
||||||
|
"""
|
||||||
|
根据{{ tableName }}id获取{{ functionName }}信息service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param {{ tableName }}_id: {{ tableName }}id
|
||||||
|
:return: {{ functionName }}信息对象
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
{{ tableName }} = await {{ tableName }}_dao.get_{{ tableName }}_by_id(auth.db, {{ tableName }}_id)
|
||||||
|
if {{ tableName }}:
|
||||||
|
return {{ tableName }}
|
||||||
|
else:
|
||||||
|
raise CustomException(msg='{{ functionName }}不存在')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def add_{{ tableName }}_services(
|
||||||
|
cls, auth: AuthSchema, page_object: {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
) -> SuccessResponse:
|
||||||
|
"""
|
||||||
|
新增{{ functionName }}service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param page_object: 新增{{ functionName }}对象
|
||||||
|
:return: 新增{{ functionName }}结果
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
|
||||||
|
try:
|
||||||
|
page_object.create_time = datetime.now()
|
||||||
|
await {{ tableName }}_dao.create(data=page_object.model_dump())
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
await auth.db.commit()
|
||||||
|
return SuccessResponse(msg='新增成功')
|
||||||
|
except Exception as e:
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
try:
|
||||||
|
await auth.db.rollback()
|
||||||
|
except:
|
||||||
|
pass # 忽略回滚错误
|
||||||
|
raise CustomException(msg=f'新增失败: {str(e)}')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def update_{{ tableName }}_services(cls, auth: AuthSchema, page_object: {{ tableName|snake_to_pascal_case }}Model) -> SuccessResponse:
|
||||||
|
"""
|
||||||
|
编辑{{ functionName }}service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param page_object: 编辑{{ functionName }}对象
|
||||||
|
:return: 编辑{{ functionName }}结果
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
|
||||||
|
# 检查必要字段是否存在
|
||||||
|
if page_object.id is None:
|
||||||
|
raise CustomException(msg='{{ functionName }}ID不能为空')
|
||||||
|
|
||||||
|
edit_{{ tableName }} = page_object.model_dump(exclude_unset=True)
|
||||||
|
{{ tableName }}_info = await cls.get_{{ tableName }}_by_id_services(auth, page_object.id)
|
||||||
|
if {{ tableName }}_info:
|
||||||
|
try:
|
||||||
|
edit_{{ tableName }}['update_time'] = datetime.now()
|
||||||
|
await {{ tableName }}_dao.update(id=page_object.id, data=edit_{{ tableName }})
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
await auth.db.commit()
|
||||||
|
return SuccessResponse(msg='更新成功')
|
||||||
|
except Exception as e:
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
try:
|
||||||
|
await auth.db.rollback()
|
||||||
|
except:
|
||||||
|
pass # 忽略回滚错误
|
||||||
|
raise CustomException(msg=f'更新失败: {str(e)}')
|
||||||
|
else:
|
||||||
|
raise CustomException(msg='{{ functionName }}不存在')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def del_{{ tableName }}_services(cls, auth: AuthSchema, ids: List[str]) -> SuccessResponse:
|
||||||
|
"""
|
||||||
|
删除{{ functionName }}service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param ids: {{ functionName }}id列表
|
||||||
|
:return: 删除{{ functionName }}结果
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
|
||||||
|
try:
|
||||||
|
id_list = [int(id) for id in ids]
|
||||||
|
await {{ tableName }}_dao.delete(ids=id_list)
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
await auth.db.commit()
|
||||||
|
return SuccessResponse(msg='删除成功')
|
||||||
|
except Exception as e:
|
||||||
|
if isinstance(auth.db, AsyncSession):
|
||||||
|
try:
|
||||||
|
await auth.db.rollback()
|
||||||
|
except:
|
||||||
|
pass # 忽略回滚错误
|
||||||
|
raise CustomException(msg=f'删除失败: {str(e)}')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def export_{{ tableName }}_list_services(cls, auth: AuthSchema, query_object: {{ tableName|snake_to_pascal_case }}PageModel) -> bytes:
|
||||||
|
"""
|
||||||
|
导出{{ functionName }}service
|
||||||
|
|
||||||
|
:param auth: 认证信息
|
||||||
|
:param query_object: 查询参数对象
|
||||||
|
:return: 导出{{ functionName }}结果
|
||||||
|
"""
|
||||||
|
# 确保db是AsyncSession类型
|
||||||
|
if not isinstance(auth.db, AsyncSession):
|
||||||
|
raise CustomException(msg='数据库会话类型不正确')
|
||||||
|
|
||||||
|
{{ tableName }}_dao = {{ tableName|snake_to_pascal_case }}Dao(auth=auth)
|
||||||
|
{{ tableName }}_list_result = await {{ tableName }}_dao.get_{{ tableName }}_list(auth.db, query_object, is_page=False)
|
||||||
|
|
||||||
|
# 这里应该实现导出逻辑,例如生成Excel文件
|
||||||
|
# 为简化起见,我们返回一个简单的文本文件
|
||||||
|
export_data = "ID,名称\n"
|
||||||
|
for item in {{ tableName }}_list_result.get("items", []):
|
||||||
|
export_data += f"{item.id},{getattr(item, 'name', '')}\n"
|
||||||
|
|
||||||
|
return export_data.encode('utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from utils.common_util import CamelCaseUtil, export_list2excel
|
||||||
|
from module_admin.entity.vo.sys_table_vo import SysTablePageModel
|
||||||
|
from module_admin.service.sys_table_service import SysTableService
|
||||||
|
from utils.page_util import PageResponseModel
|
||||||
|
from {{ packageName }}.dao.{{ tableName }}_dao import {{ tableName|snake_to_pascal_case }}Dao
|
||||||
|
from {{ packageName }}.entity.do.{{ tableName }}_do import {{ tableName|snake_to_pascal_case }}
|
||||||
|
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
||||||
|
|
||||||
|
|
||||||
|
class {{ tableName|snake_to_pascal_case }}Service:
|
||||||
|
"""
|
||||||
|
{{ tableName|snake_to_pascal_case }}管理模块服务层
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql: str) -> [list | PageResponseModel]:
|
||||||
|
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=True)
|
||||||
|
return {{ tableName }}_list
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def get_{{ tableName }}_by_id(cls, query_db: AsyncSession, {{ tableName }}_id: int) -> {{ tableName|snake_to_pascal_case }}Model:
|
||||||
|
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.get_by_id(query_db, {{ tableName }}_id)
|
||||||
|
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
|
||||||
|
return {{ tableName }}_model
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def add_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
|
||||||
|
{{ tableName }}_model = await {{ tableName|snake_to_pascal_case }}Dao.add_{{ tableName }}(query_db, query_object)
|
||||||
|
return {{ tableName }}_model
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def update_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
|
||||||
|
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.edit_{{ tableName }}(query_db, query_object)
|
||||||
|
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
|
||||||
|
return {{ tableName }}_model
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def del_{{ tableName }}(cls, query_db: AsyncSession, {{ tableName }}_ids: List[str]):
|
||||||
|
await {{ tableName|snake_to_pascal_case }}Dao.del_{{ tableName }}(query_db, {{ tableName }}_ids)
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def export_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql) -> bytes:
|
||||||
|
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=False)
|
||||||
|
filed_list = await SysTableService.get_sys_table_list(query_db, SysTablePageModel(tableName='{{ tableName }}'), is_page=False)
|
||||||
|
filtered_filed = sorted(filter(lambda x: x["show"] == '1', filed_list), key=lambda x: x["sequence"])
|
||||||
|
new_data = []
|
||||||
|
for item in {{ tableName }}_list:
|
||||||
|
mapping_dict = {}
|
||||||
|
for fild in filtered_filed:
|
||||||
|
if fild["prop"] in item:
|
||||||
|
mapping_dict[fild["label"]] = item[fild["prop"]]
|
||||||
|
new_data.append(mapping_dict)
|
||||||
|
binary_data = export_list2excel(new_data)
|
||||||
|
return binary_data
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
# -*- coding:utf-8 -*-
|
|
||||||
|
|
||||||
from typing import List
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
from utils.common_util import CamelCaseUtil, export_list2excel
|
|
||||||
from module_admin.entity.vo.sys_table_vo import SysTablePageModel
|
|
||||||
from module_admin.service.sys_table_service import SysTableService
|
|
||||||
from utils.page_util import PageResponseModel
|
|
||||||
from {{ packageName }}.dao.{{ tableName }}_dao import {{ tableName|snake_to_pascal_case }}Dao
|
|
||||||
from {{ packageName }}.entity.do.{{ tableName }}_do import {{ tableName|snake_to_pascal_case }}
|
|
||||||
from {{ packageName }}.entity.vo.{{ tableName }}_vo import {{ tableName|snake_to_pascal_case }}PageModel, {{ tableName|snake_to_pascal_case }}Model
|
|
||||||
|
|
||||||
|
|
||||||
class {{ tableName|snake_to_pascal_case }}Service:
|
|
||||||
"""
|
|
||||||
{{ tableName|snake_to_pascal_case }}管理模块服务层
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def get_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql: str) -> [list | PageResponseModel]:
|
|
||||||
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=True)
|
|
||||||
return {{ tableName }}_list
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def get_{{ tableName }}_by_id(cls, query_db: AsyncSession, {{ tableName }}_id: int) -> {{ tableName|snake_to_pascal_case }}Model:
|
|
||||||
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.get_by_id(query_db, {{ tableName }}_id)
|
|
||||||
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
|
|
||||||
return {{ tableName }}_model
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def add_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
|
|
||||||
{{ tableName }}_model = await {{ tableName|snake_to_pascal_case }}Dao.add_{{ tableName }}(query_db, query_object)
|
|
||||||
return {{ tableName }}_model
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def update_{{ tableName }}(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}Model) -> {{ tableName|snake_to_pascal_case }}Model:
|
|
||||||
{{ tableName }} = await {{ tableName|snake_to_pascal_case }}Dao.edit_{{ tableName }}(query_db, query_object)
|
|
||||||
{{ tableName }}_model = {{ tableName|snake_to_pascal_case }}Model(**CamelCaseUtil.transform_result({{ tableName }}))
|
|
||||||
return {{ tableName }}_model
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def del_{{ tableName }}(cls, query_db: AsyncSession, {{ tableName }}_ids: List[str]):
|
|
||||||
await {{ tableName|snake_to_pascal_case }}Dao.del_{{ tableName }}(query_db, {{ tableName }}_ids)
|
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
async def export_{{ tableName }}_list(cls, query_db: AsyncSession, query_object: {{ tableName|snake_to_pascal_case }}PageModel, data_scope_sql) -> bytes:
|
|
||||||
{{ tableName }}_list = await {{ tableName|snake_to_pascal_case }}Dao.get_{{ tableName }}_list(query_db, query_object, data_scope_sql, is_page=False)
|
|
||||||
filed_list = await SysTableService.get_sys_table_list(query_db, SysTablePageModel(tableName='{{ tableName }}'), is_page=False)
|
|
||||||
filtered_filed = sorted(filter(lambda x: x["show"] == '1', filed_list), key=lambda x: x["sequence"])
|
|
||||||
new_data = []
|
|
||||||
for item in {{ tableName }}_list:
|
|
||||||
mapping_dict = {}
|
|
||||||
for fild in filtered_filed:
|
|
||||||
if fild["prop"] in item:
|
|
||||||
mapping_dict[fild["label"]] = item[fild["prop"]]
|
|
||||||
new_data.append(mapping_dict)
|
|
||||||
binary_data = export_list2excel(new_data)
|
|
||||||
return binary_data
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
-- 菜单 SQL
|
-- 菜单 SQL
|
||||||
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
|
||||||
values('{{functionName}}', '{{parentMenuId}}', '1', '{{moduleName}}_{{businessName}}', '{{moduleName}}/{{businessName}}/index', 1, 0, 'C', '0', '0', '{{permissionPrefix}}:list', '#', 'admin', sysdate(), '', null, '{{functionName}}菜单');
|
values('{{functionName}}', '{{parentMenuId}}', '1', '{{businessName}}', '{{moduleName}}/{{businessName}}/index', 1, 0, 'C', '0', '0', '{{permissionPrefix}}:list', '#', 'admin', sysdate(), '', null, '{{functionName}}菜单');
|
||||||
|
|
||||||
-- 按钮父菜单ID
|
-- 按钮父菜单ID
|
||||||
SELECT @parentId := LAST_INSERT_ID();
|
SELECT @parentId := LAST_INSERT_ID();
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ export function list{{BusinessName}}(query) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询{{functionName}}详细
|
// 查询{{functionName}}详细
|
||||||
export function get{{BusinessName}}({{pkColumn.pythonField | snake_to_camel}}) {
|
export function get{{BusinessName}}(id) {
|
||||||
return request({
|
return request({
|
||||||
url: '/{{moduleName}}/{{businessName}}/getById/' + {{pkColumn.pythonField | snake_to_camel}},
|
url: '/{{moduleName}}/{{businessName}}/' + id,
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -20,7 +20,7 @@ export function get{{BusinessName}}({{pkColumn.pythonField | snake_to_camel}}) {
|
|||||||
// 新增{{functionName}}
|
// 新增{{functionName}}
|
||||||
export function add{{BusinessName}}(data) {
|
export function add{{BusinessName}}(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/{{moduleName}}/{{businessName}}/add',
|
url: '/{{moduleName}}/{{businessName}}/create',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@@ -36,9 +36,9 @@ export function update{{BusinessName}}(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 删除{{functionName}}
|
// 删除{{functionName}}
|
||||||
export function del{{BusinessName}}({{pkColumn.pythonField | snake_to_camel}}) {
|
export function del{{BusinessName}}(ids) {
|
||||||
return request({
|
return request({
|
||||||
url: '/{{moduleName}}/{{businessName}}/delete/' + {{pkColumn.pythonField | snake_to_camel}},
|
url: '/{{moduleName}}/{{businessName}}/' + ids,
|
||||||
method: 'delete'
|
method: 'delete'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ class TemplateInitializer:
|
|||||||
:return: Jinja2 环境对象
|
:return: Jinja2 环境对象
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
template_dir = os.path.join(os.getcwd(), 'module_generator', 'templates')
|
# 修复模板路径,使用正确的相对路径
|
||||||
|
template_dir = os.path.join(os.path.dirname(__file__), '..', 'api', 'v1', 'module_generator', 'gencode', 'templates')
|
||||||
|
template_dir = os.path.abspath(template_dir)
|
||||||
env = Environment(
|
env = Environment(
|
||||||
loader=FileSystemLoader(template_dir),
|
loader=FileSystemLoader(template_dir),
|
||||||
keep_trailing_newline=True,
|
keep_trailing_newline=True,
|
||||||
@@ -147,8 +149,12 @@ class TemplateUtils:
|
|||||||
sub_table = gen_table.sub_table
|
sub_table = gen_table.sub_table
|
||||||
sub_table_name = gen_table.sub_table_name
|
sub_table_name = gen_table.sub_table_name
|
||||||
sub_table_fk_name = gen_table.sub_table_fk_name
|
sub_table_fk_name = gen_table.sub_table_fk_name
|
||||||
sub_class_name = sub_table.class_name
|
# 修复类型检查问题,确保sub_table存在
|
||||||
sub_table_fk_class_name = StringUtil.convert_to_camel_case(sub_table_fk_name)
|
if sub_table:
|
||||||
|
sub_class_name = sub_table.class_name or ""
|
||||||
|
else:
|
||||||
|
sub_class_name = ""
|
||||||
|
sub_table_fk_class_name = StringUtil.convert_to_camel_case(sub_table_fk_name or "")
|
||||||
context['subTable'] = sub_table
|
context['subTable'] = sub_table
|
||||||
context['subTableName'] = sub_table_name
|
context['subTableName'] = sub_table_name
|
||||||
context['subTableFkName'] = sub_table_fk_name
|
context['subTableFkName'] = sub_table_fk_name
|
||||||
@@ -170,20 +176,20 @@ class TemplateUtils:
|
|||||||
if tpl_web_type == 'element-plus':
|
if tpl_web_type == 'element-plus':
|
||||||
use_web_type = 'vue/v3'
|
use_web_type = 'vue/v3'
|
||||||
templates = [
|
templates = [
|
||||||
'python/controller.py.jinja2',
|
'python/controller.py.j2',
|
||||||
'python/dao.py.jinja2',
|
'python/crud.py.j2',
|
||||||
'python/do.py.jinja2',
|
'python/model.py.j2',
|
||||||
'python/service.py.jinja2',
|
'python/schema.py.j2',
|
||||||
'python/vo.py.jinja2',
|
'python/service.py.j2',
|
||||||
'sql/sql.jinja2',
|
'sql/sql.j2',
|
||||||
'js/api.js.jinja2',
|
'vue/api.js.j2',
|
||||||
]
|
]
|
||||||
if tpl_category == GenConstant.TPL_CRUD:
|
if tpl_category == GenConstant.TPL_CRUD:
|
||||||
templates.append(f'{use_web_type}/index.vue.jinja2')
|
templates.append(f'{use_web_type}/index.vue.j2')
|
||||||
elif tpl_category == GenConstant.TPL_TREE:
|
elif tpl_category == GenConstant.TPL_TREE:
|
||||||
templates.append(f'{use_web_type}/index-tree.vue.jinja2')
|
templates.append(f'{use_web_type}/index-tree.vue.j2')
|
||||||
elif tpl_category == GenConstant.TPL_SUB:
|
elif tpl_category == GenConstant.TPL_SUB:
|
||||||
templates.append(f'{use_web_type}/index.vue.jinja2')
|
templates.append(f'{use_web_type}/index.vue.j2')
|
||||||
# templates.append('python/sub-domain.python.jinja2')
|
# templates.append('python/sub-domain.python.jinja2')
|
||||||
return templates
|
return templates
|
||||||
|
|
||||||
@@ -203,21 +209,21 @@ class TemplateUtils:
|
|||||||
vue_path = cls.FRONTEND_PROJECT_PATH
|
vue_path = cls.FRONTEND_PROJECT_PATH
|
||||||
python_path = f'{cls.BACKEND_PROJECT_PATH}/{package_name.replace(".", "/")}'
|
python_path = f'{cls.BACKEND_PROJECT_PATH}/{package_name.replace(".", "/")}'
|
||||||
|
|
||||||
if 'controller.py.jinja2' in template:
|
if 'controller.py.j2' in template:
|
||||||
return f'{python_path}/controller/{business_name}_controller.py'
|
return f'{python_path}/{business_name}_controller.py'
|
||||||
elif 'dao.py.jinja2' in template:
|
elif 'crud.py.j2' in template:
|
||||||
return f'{python_path}/dao/{business_name}_dao.py'
|
return f'{python_path}/{business_name}_crud.py'
|
||||||
elif 'do.py.jinja2' in template:
|
elif 'model.py.j2' in template:
|
||||||
return f'{python_path}/entity/do/{business_name}_do.py'
|
return f'{python_path}/{business_name}_model.py'
|
||||||
elif 'service.py.jinja2' in template:
|
elif 'service.py.j2' in template:
|
||||||
return f'{python_path}/service/{business_name}_service.py'
|
return f'{python_path}/{business_name}_service.py'
|
||||||
elif 'vo.py.jinja2' in template:
|
elif 'schema.py.j2' in template:
|
||||||
return f'{python_path}/entity/vo/{business_name}_vo.py'
|
return f'{python_path}/{business_name}_schema.py'
|
||||||
elif 'sql.jinja2' in template:
|
elif 'sql.j2' in template:
|
||||||
return f'{cls.BACKEND_PROJECT_PATH}/sql/{business_name}_menu.sql'
|
return f'{cls.BACKEND_PROJECT_PATH}/sql/{business_name}_menu.sql'
|
||||||
elif 'api.js.jinja2' in template:
|
elif 'api.js.j2' in template:
|
||||||
return f'{vue_path}/api/{module_name}/{business_name}.js'
|
return f'{vue_path}/api/{module_name}/{business_name}.js'
|
||||||
elif 'index.vue.jinja2' in template or 'index-tree.vue.jinja2' in template:
|
elif 'index.vue.j2' in template or 'index-tree.vue.j2' in template:
|
||||||
return f'{vue_path}/views/{module_name}/{business_name}/index.vue'
|
return f'{vue_path}/views/{module_name}/{business_name}/index.vue'
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@@ -246,7 +252,8 @@ class TemplateUtils:
|
|||||||
import_list.add(f'from datetime import {column.python_type}')
|
import_list.add(f'from datetime import {column.python_type}')
|
||||||
elif column.python_type == GenConstant.TYPE_DECIMAL:
|
elif column.python_type == GenConstant.TYPE_DECIMAL:
|
||||||
import_list.add('from decimal import Decimal')
|
import_list.add('from decimal import Decimal')
|
||||||
if gen_table.sub:
|
# 修复类型检查问题,确保sub_table存在且有columns属性
|
||||||
|
if gen_table.sub and gen_table.sub_table:
|
||||||
sub_columns = gen_table.sub_table.columns or []
|
sub_columns = gen_table.sub_table.columns or []
|
||||||
for sub_column in sub_columns:
|
for sub_column in sub_columns:
|
||||||
if sub_column.python_type in GenConstant.TYPE_DATE:
|
if sub_column.python_type in GenConstant.TYPE_DATE:
|
||||||
@@ -273,7 +280,8 @@ class TemplateUtils:
|
|||||||
import_list.add(
|
import_list.add(
|
||||||
f'from sqlalchemy import {StringUtil.get_mapping_value_by_key_ignore_case(GenConstant.DB_TO_SQLALCHEMY_TYPE_MAPPING, data_type)}'
|
f'from sqlalchemy import {StringUtil.get_mapping_value_by_key_ignore_case(GenConstant.DB_TO_SQLALCHEMY_TYPE_MAPPING, data_type)}'
|
||||||
)
|
)
|
||||||
if gen_table.sub:
|
# 修复类型检查问题,确保sub_table存在且有columns属性
|
||||||
|
if gen_table.sub and gen_table.sub_table:
|
||||||
import_list.add('from sqlalchemy import ForeignKey')
|
import_list.add('from sqlalchemy import ForeignKey')
|
||||||
sub_columns = gen_table.sub_table.columns or []
|
sub_columns = gen_table.sub_table.columns or []
|
||||||
for sub_column in sub_columns:
|
for sub_column in sub_columns:
|
||||||
|
|||||||
Reference in New Issue
Block a user