Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 7 additions & 8 deletions backend/app/api/v1/module_generator/gencode/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,7 @@ async def get_gen_table_list(self, search: Optional[GenTableQueryParam] = None,
- Sequence[GenTableModel]: 业务表列表信息。
"""
# 使用基础CRUD的list与like检索
search_dict: Dict = {}
if search and search.table_name:
search_dict["table_name"] = ("like", search.table_name)
if search and search.table_comment:
search_dict["table_comment"] = ("like", search.table_comment)
return await self.list(search=search_dict, order_by=[{"created_at": "desc"}], preload=preload)
return await self.list(search=search.__dict__, order_by=[{"created_at": "desc"}], preload=preload)

async def add_gen_table(self, add_model: GenTableSchema) -> GenTableModel:
"""
Expand All @@ -111,7 +106,9 @@ async def edit_gen_table(self, table_id: int, edit_model: GenTableSchema) -> Gen
返回:
- GenTableSchema: 修改后的业务表信息模型。
"""
obj = await self.update(id=table_id, data=edit_model)
# 排除嵌套对象字段,避免SQLAlchemy尝试直接将字典设置到模型实例上
data_dict = edit_model.model_dump(exclude_unset=True, exclude={"columns", "pk_column", "sub_table", "sub"})
obj = await self.update(id=table_id, data=data_dict)
return GenTableSchema.model_validate(obj)

async def delete_gen_table(self, ids: List[int]) -> None:
Expand Down Expand Up @@ -520,7 +517,9 @@ async def update_gen_table_column_crud(self, id: int, data: GenTableColumnSchema
返回:
- Optional[GenTableColumnModel]: 业务表字段列表信息对象。
"""
return await self.update(id=id, data=data)
# 将对象转换为字典,避免SQLAlchemy直接操作对象时出现的状态问题
data_dict = data.model_dump(exclude_unset=True)
return await self.update(id=id, data=data_dict)

async def delete_gen_table_column_by_table_id_dao(self, table_ids: List[int]) -> None:
"""根据业务表ID批量删除业务表字段。
Expand Down
4 changes: 4 additions & 0 deletions backend/app/api/v1/module_generator/gencode/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from sqlalchemy import String, Integer, ForeignKey
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.config.setting import settings
from app.core.base_model import CreatorMixin
from app.utils.common_util import SqlalchemyUtil


class GenTableModel(CreatorMixin):
Expand All @@ -17,6 +19,8 @@ class GenTableModel(CreatorMixin):

table_name: Mapped[Optional[str]] = mapped_column(String(200), nullable=True, default='', comment='表名称')
table_comment: Mapped[Optional[str]] = mapped_column(String(500), nullable=True, default='', comment='表描述')
sub_table_name : Mapped[Optional[str]] = mapped_column(String(64), nullable=True, server_default=SqlalchemyUtil.get_server_default_null(settings.DATABASE_TYPE), comment='关联子表的表名',)
sub_table_fk_name: Mapped[Optional[str]] = mapped_column(String(64), nullable=True, server_default=SqlalchemyUtil.get_server_default_null(settings.DATABASE_TYPE), comment='子表关联的外键名',)
class_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, default='', comment='实体类名称')
package_name: Mapped[Optional[str]] = mapped_column(String(100), nullable=True, comment='生成包路径')
module_name: Mapped[Optional[str]] = mapped_column(String(30), nullable=True, comment='生成模块名')
Expand Down
11 changes: 4 additions & 7 deletions backend/app/api/v1/module_generator/gencode/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,20 +37,19 @@ class GenTableBaseSchema(BaseModel):
"""
model_config = ConfigDict(from_attributes=True)

table_id: Optional[int] = Field(default=None, description='编号')
table_name: str= Field(..., description='表名称')
table_comment: Optional[str] = Field(default=None, description='表描述')
sub_table_name: Optional[str] = Field(default=None, description='关联子表的表名')
sub_table_fk_name: Optional[str] = Field(default=None, description='子表关联的外键名')
class_name: Optional[str] = Field(default=None, description='实体类名称')
package_name: Optional[str] = Field(default=None, description='生成包路径')
module_name: Optional[str] = Field(default=None, description='生成模块名')
business_name: Optional[str] = Field(default=None, description='生成业务名')
function_name: Optional[str] = Field(default=None, description='生成功能名')
gen_type: Optional[Literal['0', '1']] = Field(default=None, description='生成代码方式(0zip压缩包 1生成项目路径)')
options: Optional[str] = Field(default=None, description='其它生成选项')
options: Optional[str] = Field(default=None, description='其它生成选项(JSON字符串)')
description: Optional[str] = Field(default=None, description='功能描述')

params: Optional[GenTableOptionSchema] = Field(default=None, description='前端传递过来的表附加信息,转换成json字符串后放到options')


class GenTableSchema(GenTableBaseSchema):
"""代码生成业务表更新模型(扩展聚合字段)。
Expand All @@ -62,6 +61,7 @@ class GenTableSchema(GenTableBaseSchema):
columns: Optional[List['GenTableColumnOutSchema']] = Field(default=None, description='表列信息')
parent_menu_id: Optional[int] = Field(default=None, description='上级菜单ID字段')
parent_menu_name: Optional[str] = Field(default=None, description='上级菜单名称字段')
sub: Optional[bool] = Field(default=None, description='是否为子表')


class GenTableOutSchema(GenTableSchema, BaseSchema):
Expand All @@ -70,9 +70,6 @@ class GenTableOutSchema(GenTableSchema, BaseSchema):
- 兼容:既支持传入ORM对象,也支持字典输入。
"""
model_config = ConfigDict(from_attributes=True)

# 修复:确保columns字段默认为空列表而不是None
columns: Optional[List['GenTableColumnOutSchema']] = Field(default_factory=list, description='表列信息')


class GenTableColumnSchema(BaseModel):
Expand Down
93 changes: 48 additions & 45 deletions backend/app/api/v1/module_generator/gencode/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
from app.config.setting import settings
from app.core.logger import logger
from app.core.exceptions import CustomException
from app.common.constant import GenConstant
from app.api.v1.module_system.auth.schema import AuthSchema
from app.utils.gen_util import GenUtils
from app.utils.jinja2_template_util import Jinja2TemplateUtil
from .schema import GenTableOptionSchema, GenTableSchema, GenTableOutSchema, GenTableColumnSchema, GenTableColumnOutSchema
from .schema import GenTableSchema, GenTableOutSchema, GenTableColumnSchema, GenTableColumnOutSchema
from .param import GenTableQueryParam
from .crud import GenTableColumnCRUD, GenTableCRUD

Expand Down Expand Up @@ -43,13 +42,6 @@ async def get_gen_table_detail_service(cls, auth: AuthSchema, table_id: int) ->
gen_table = await cls.get_gen_table_by_id_service(auth, table_id)
gen_tables = await cls.get_gen_table_all_service(auth)
gen_columns = await GenTableColumnService.get_gen_table_column_list_by_table_id_service(auth, table_id)
# 修复:确保options不为None再解析
if gen_table.options:
try:
table_options = GenTableOptionSchema(**json.loads(gen_table.options))
gen_table.parent_menu_id = table_options.parent_menu_id
except Exception as e:
logger.warning(f"解析表选项时出错: {str(e)}")
gen_table.columns = gen_columns
return dict(info=gen_table, rows=gen_columns, tables=gen_tables)

Expand All @@ -71,7 +63,7 @@ async def get_gen_table_list_service(cls, auth: AuthSchema, search: GenTableQuer

@classmethod
@handle_service_exception
async def get_gen_db_table_list_service(cls, auth: AuthSchema, search: GenTableQueryParam, order_by: Optional[List[Dict[str, str]]] = None) -> list[Any]:
async def get_gen_db_table_list_service(cls, auth: AuthSchema, search: GenTableQueryParam) -> list[Any]:
"""获取数据库表列表(跨方言)。
- 备注:返回已转换为字典的结构,适用于前端直接展示;排序参数保留扩展位但当前未使用。
"""
Expand All @@ -89,12 +81,6 @@ async def get_gen_db_table_list_by_name_service(cls, auth: AuthSchema, table_nam
raise CustomException(msg="表名列表不能为空")

gen_db_table_list_result = await GenTableCRUD(auth).get_db_table_list_by_names(table_names)

# 检查是否有未找到的表
found_table_names = [table.table_name for table in gen_db_table_list_result]
missing_tables = [name for name in table_names if name not in found_table_names]
if missing_tables:
raise CustomException(msg=f"以下数据表不存在: {', '.join(missing_tables)}")

# 修复:将GenDBTableSchema对象转换为字典后再传递给GenTableOutSchema
result = []
Expand All @@ -119,9 +105,6 @@ async def import_gen_table_service(cls, auth: AuthSchema, gen_table_list: List[G
existing_tables = []
for table in gen_table_list:
table_name = table.table_name
# 确保table_name不为None
if table_name is None:
raise CustomException(msg="表名不能为空")
# 检查表是否已存在
existing_table = await GenTableCRUD(auth).get_gen_table_by_name(table_name)
if existing_table:
Expand All @@ -137,21 +120,22 @@ async def import_gen_table_service(cls, auth: AuthSchema, gen_table_list: List[G
GenUtils.init_table(table)
add_gen_table = await GenTableCRUD(auth).add_gen_table(table)
if add_gen_table:
table.table_id = add_gen_table.id
table.id = add_gen_table.id
# 获取数据库表的字段信息
gen_table_columns = await GenTableColumnCRUD(auth).get_gen_db_table_columns_by_name(table_name)

# 为每个字段初始化并保存到数据库
for column in gen_table_columns:
# 将GenTableColumnOutSchema转换为GenTableColumnSchema
# 将GenTableColumnOutSchema转换为GenTableColumnSchema,确保is_*字段为字符串格式
column_schema = GenTableColumnSchema(
table_id=table.table_id,
table_id=table.id,
column_name=column.column_name,
column_comment=column.column_comment,
column_type=column.column_type,
is_pk=column.is_pk,
is_increment=column.is_increment,
is_required=column.is_required,
# 确保这些字段为字符串格式,'1'表示true,'0'表示false
is_pk=str(column.is_pk) if column.is_pk is not None else '0',
is_increment=str(column.is_increment) if column.is_increment is not None else '0',
is_required=str(column.is_required) if column.is_required is not None else '0',
sort=column.sort
)
# 初始化字段属性
Expand Down Expand Up @@ -235,25 +219,21 @@ def __get_table_names(cls, sql_statements: List[Expression | None]) -> List[str]
async def update_gen_table_service(cls, auth: AuthSchema, data: GenTableSchema, table_id: int) -> Dict[str, Any]:
"""编辑业务表信息(含选项与字段)。
- 备注:将`params`序列化写入`options`以持久化;仅更新存在`id`的列,避免误创建。
"""

"""
# 处理params为None的情况
gen_table_info = await cls.get_gen_table_by_id_service(auth, table_id)
if gen_table_info.id:
try:
# 处理params为None的情况
edit_gen_table = data.model_dump(exclude_unset=True, by_alias=True)
params = edit_gen_table.get('params')
if params:
edit_gen_table['options'] = json.dumps(params)
# 将字典转换为GenTableSchema对象
gen_table_schema = GenTableSchema(**edit_gen_table)
result = await GenTableCRUD(auth).edit_gen_table(table_id, gen_table_schema)
# 直接调用edit_gen_table方法,它会在内部处理排除嵌套字段的逻辑
result = await GenTableCRUD(auth).edit_gen_table(table_id, data)

# 处理data.columns为None的情况
if data.columns:
for gen_table_column in data.columns:
# 确保column有id字段
if hasattr(gen_table_column, 'id') and gen_table_column.id:
await GenTableColumnCRUD(auth).update_gen_table_column_crud(gen_table_column.id, gen_table_column)
column_schema = GenTableColumnSchema(**gen_table_column.model_dump())
await GenTableColumnCRUD(auth).update_gen_table_column_crud(gen_table_column.id, column_schema)
return result.model_dump()
except Exception as e:
raise CustomException(msg=str(e))
Expand Down Expand Up @@ -287,12 +267,8 @@ async def get_gen_table_by_id_service(cls, auth: AuthSchema, table_id: int) -> G
raise CustomException(msg='业务表不存在')

result = GenTableOutSchema.model_validate(gen_table)
# 确保columns字段为列表,即使为None
if result.columns is None:
result.columns = []

return result


@classmethod
@handle_service_exception
Expand Down Expand Up @@ -412,10 +388,7 @@ async def sync_db_service(cls, auth: AuthSchema, table_name: str) -> None:
gen_table = await GenTableCRUD(auth).get_gen_table_by_name(table_name)
if not gen_table:
raise CustomException(msg='业务表不存在')
table = GenTableSchema.model_validate(gen_table)
# 关键修复:确保 table.table_id 正确设置为持久化的表ID,否则列无法关联到该表
if getattr(table, 'table_id', None) is None:
table.table_id = getattr(gen_table, 'id', None)
table = GenTableOutSchema.model_validate(gen_table)
table_columns = table.columns or []
table_column_map = {column.column_name: column for column in table_columns}
db_table_columns = await GenTableColumnCRUD(auth).get_gen_db_table_columns_by_name(table_name)
Expand Down Expand Up @@ -457,7 +430,7 @@ def keep_str(orig, current):
await GenTableColumnCRUD(auth).create_gen_table_column_crud(column)
else:
# 设置table_id以确保新字段能正确关联到表
column.table_id = table.table_id
column.table_id = table.id
await GenTableColumnCRUD(auth).create_gen_table_column_crud(column)
del_columns = [column for column in table_columns if column.column_name not in db_table_column_names]
if del_columns:
Expand Down Expand Up @@ -542,8 +515,38 @@ async def get_gen_table_column_list_by_table_id_service(cls, auth: AuthSchema, t
result = []
for gen_table_column in gen_table_column_list_result:
try:
# 转换为输出模型前确保必要字段正确设置
# 确保is_*字段为字符串格式
if hasattr(gen_table_column, 'is_pk') and gen_table_column.is_pk is not None and not isinstance(gen_table_column.is_pk, str):
gen_table_column.is_pk = str(gen_table_column.is_pk)
if hasattr(gen_table_column, 'is_increment') and gen_table_column.is_increment is not None and not isinstance(gen_table_column.is_increment, str):
gen_table_column.is_increment = str(gen_table_column.is_increment)
if hasattr(gen_table_column, 'is_required') and gen_table_column.is_required is not None and not isinstance(gen_table_column.is_required, str):
gen_table_column.is_required = str(gen_table_column.is_required)
if hasattr(gen_table_column, 'is_unique') and gen_table_column.is_unique is not None and not isinstance(gen_table_column.is_unique, str):
gen_table_column.is_unique = str(gen_table_column.is_unique)
if hasattr(gen_table_column, 'is_insert') and gen_table_column.is_insert is not None and not isinstance(gen_table_column.is_insert, str):
gen_table_column.is_insert = str(gen_table_column.is_insert)
if hasattr(gen_table_column, 'is_edit') and gen_table_column.is_edit is not None and not isinstance(gen_table_column.is_edit, str):
gen_table_column.is_edit = str(gen_table_column.is_edit)
if hasattr(gen_table_column, 'is_list') and gen_table_column.is_list is not None and not isinstance(gen_table_column.is_list, str):
gen_table_column.is_list = str(gen_table_column.is_list)
if hasattr(gen_table_column, 'is_query') and gen_table_column.is_query is not None and not isinstance(gen_table_column.is_query, str):
gen_table_column.is_query = str(gen_table_column.is_query)

# 转换为输出模型
column_out = GenTableColumnOutSchema.model_validate(gen_table_column)

# 确保输出模型中的布尔字段正确设置
column_out.pk = column_out.is_pk == '1'
column_out.increment = column_out.is_increment == '1'
column_out.required = column_out.is_required == '1'
column_out.unique = column_out.is_unique == '1'
column_out.insert = column_out.is_insert == '1'
column_out.edit = column_out.is_edit == '1'
column_out.list = column_out.is_list == '1'
column_out.query = column_out.is_query == '1'

result.append(column_out)
except Exception as e:
logger.warning(f"转换字段模型时出错: {str(e)}")
Expand Down
14 changes: 7 additions & 7 deletions backend/app/common/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,28 +413,28 @@ class GenConstant:
'decimal',
]
# 页面不需要显示的添加字段
COLUMNNAME_NOT_ADD_SHOW = ['create_by', 'create_time']
COLUMNNAME_NOT_ADD_SHOW = ['created_at', 'updated_at']

# 页面不需要显示的编辑字段
COLUMNNAME_NOT_EDIT_SHOW = ['updated_at']

# 页面不需要编辑字段
COLUMNNAME_NOT_EDIT = ["id", "create_by", "dept_id", "create_time", "del_flag", "update_time"]
COLUMNNAME_NOT_EDIT = ["id", "description", "created_at", "updated_at"]

# 页面不需要显示的列表字段
COLUMNNAME_NOT_LIST = ["id", "create_by", "dept_id", "create_time", "del_flag", "update_time"]
COLUMNNAME_NOT_LIST = ["id", "description", "created_at", "updated_at"]

# 页面不需要查询字段
COLUMNNAME_NOT_QUERY = ["id", "create_by", "dept_id", "create_time", "del_flag", "update_by", "update_time", "remark"]
COLUMNNAME_NOT_QUERY = ["id", "description", "created_at", "updated_at"]

# Crud基类字段
CRUD_COLUMN_NOT_EDIT = ["create_by", "dept_id", "create_time", "del_flag", "update_time"]
CRUD_COLUMN_NOT_EDIT = ["create_by", "description", "created_at", "updated_at"]

# 实体基类字段
BASE_ENTITY = ['id', 'create_time', 'update_time', "create_by", "dept_id", 'del_flag']
BASE_ENTITY = ['id', 'created_at', 'updated_at', "description"]

# Tree基类字段
TREE_ENTITY = ['parentName', 'parentId', 'orderNum', 'ancestors', 'children']
TREE_ENTITY = ['parent_name', 'parent_id', 'order', 'ancestors', 'children']

# 文本框
HTML_INPUT = 'input'
Expand Down
3 changes: 3 additions & 0 deletions backend/app/config/setting.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ def FASTAPI_CONFIG(self) -> dict[str, Any]:
@property
def UVICORN_CONFIG(self) -> Dict[str, Any]:
"""获取Uvicorn配置"""
# 确保日志目录存在
self.LOGGER_DIR.mkdir(parents=True, exist_ok=True)

return {
"host": self.SERVER_HOST,
"port": self.SERVER_PORT,
Expand Down
Loading