diff --git a/backend/app/api/v1/module_generator/gencode/crud.py b/backend/app/api/v1/module_generator/gencode/crud.py
index f2a95a0c..d61dd6c7 100644
--- a/backend/app/api/v1/module_generator/gencode/crud.py
+++ b/backend/app/api/v1/module_generator/gencode/crud.py
@@ -325,6 +325,24 @@ class GenTableCRUD(CRUDBase[GenTableModel, GenTableSchema, GenTableSchema]):
log.error(f"创建表时发生错误: {e}")
return False
+ async def execute_sql(self, sql: str) -> bool:
+ """
+ 执行SQL语句。
+
+ 参数:
+ - sql (str): 要执行的SQL语句。
+
+ 返回:
+ - bool: 是否执行成功。
+ """
+ try:
+ # 执行SQL但不手动提交事务,由框架管理事务生命周期
+ await self.auth.db.execute(text(sql))
+ return True
+ except Exception as e:
+ log.error(f"执行SQL时发生错误: {e}")
+ return False
+
class GenTableColumnCRUD(CRUDBase[GenTableColumnModel, GenTableColumnSchema, GenTableColumnSchema]):
"""代码生成业务表字段模块数据库操作层"""
diff --git a/backend/app/api/v1/module_generator/gencode/service.py b/backend/app/api/v1/module_generator/gencode/service.py
index 5383ad1d..51bc1329 100644
--- a/backend/app/api/v1/module_generator/gencode/service.py
+++ b/backend/app/api/v1/module_generator/gencode/service.py
@@ -2,6 +2,7 @@
import io
import os
+from pathlib import Path
import zipfile
from typing import Any
from sqlglot.expressions import Add, Alter, Create, Delete, Drop, Expression, Insert, Table, TruncateTable, Update
@@ -185,6 +186,43 @@ class GenTableService:
except Exception as e:
raise CustomException(msg=f'创建表结构失败: {str(e)}')
+ @classmethod
+ @handle_service_exception
+ async def execute_sql_service(cls, auth: AuthSchema, gen_table: GenTableOutSchema) -> bool:
+ """
+ 执行菜单 SQL(INSERT / DO 块)并写入 sys_menu。
+ - 仅处理菜单 SQL,不再混杂建表逻辑;
+ - 文件不存在时给出友好提示;
+ - 统一异常信息,日志与业务提示分离。
+ """
+ sql_path = f'{BASE_DIR}/sql/menu/{gen_table.module_name}/{gen_table.business_name}.sql'
+
+ # 文件存在性前置检查,避免多余解析开销
+ if not os.path.isfile(sql_path):
+ raise CustomException(msg=f'菜单 SQL 文件不存在: {sql_path}')
+
+ sql = Path(sql_path).read_text(encoding='utf-8').strip()
+ if not sql:
+ raise CustomException(msg='菜单 SQL 文件内容为空')
+
+ # 仅做语法校验,不限制关键字;真正的语义安全由数据库权限控制
+ try:
+ statements = sqlglot_parse(sql, dialect=settings.DATABASE_TYPE)
+ if not statements:
+ raise CustomException(msg='菜单 SQL 语法解析失败,请检查文件内容')
+ except Exception as e:
+ log.error(f'菜单 SQL 解析异常: {e}')
+ raise CustomException(msg='菜单 SQL 语法错误,请检查文件内容')
+
+ # 执行 SQL
+ try:
+ await GenTableCRUD(auth).execute_sql(sql)
+ log.info(f'成功执行菜单 SQL: {sql_path}')
+ return True
+ except Exception as e:
+ log.error(f'菜单 SQL 执行失败: {e}')
+ raise CustomException(msg='菜单 SQL 执行失败,请确认语句及数据库状态')
+
@classmethod
def __is_valid_create_table(cls, sql_statements: list[Expression | None]) -> bool:
"""
@@ -349,6 +387,8 @@ class GenTableService:
f.write(render_content)
except Exception as e:
raise CustomException(msg=f'渲染模板失败,表名:{gen_table_schema.table_name},详细错误信息:{str(e)}')
+
+ await cls.execute_sql_service(auth, gen_table_schema)
return True
@classmethod
diff --git a/backend/app/api/v1/module_generator/gencode/templates/python/schema.py.j2 b/backend/app/api/v1/module_generator/gencode/templates/python/schema.py.j2
index 17bd9060..70d0aa22 100644
--- a/backend/app/api/v1/module_generator/gencode/templates/python/schema.py.j2
+++ b/backend/app/api/v1/module_generator/gencode/templates/python/schema.py.j2
@@ -53,7 +53,7 @@ class {{ class_name }}QueryParam:
{% endif %}
{% endfor %}
{% for column in columns %}
- {% if column.query_type == 'EQ' %}
+ {% if column.query_type == 'EQ' and column.column_name not in ['created_time', 'updated_time'] %}
{{ column.column_name }}: {{ column.python_type }} | None = Query(None, description="{{ column.column_comment }}"),
{% endif %}
{% endfor %}
@@ -70,7 +70,7 @@ class {{ class_name }}QueryParam:
{% if column.query_type == 'LIKE' %}
# 模糊查询字段
self.{{ column.column_name }} = ("like", {{ column.column_name }})
- {% elif column.query_type == 'EQ' and column.column_name %}
+ {% elif column.query_type == 'EQ' and column.column_name not in ['created_time', 'updated_time'] %}
# 精确查询字段
self.{{ column.column_name }} = {{ column.column_name }}
{% endif %}
diff --git a/backend/app/api/v1/module_generator/gencode/templates/sql/sql.sql.j2 b/backend/app/api/v1/module_generator/gencode/templates/sql/sql.sql.j2
index d9511e0a..b05cd4b4 100644
--- a/backend/app/api/v1/module_generator/gencode/templates/sql/sql.sql.j2
+++ b/backend/app/api/v1/module_generator/gencode/templates/sql/sql.sql.j2
@@ -12,7 +12,7 @@
INSERT INTO {{ sys_menu }}
(`name`, `type`, {{ order_col }}, `permission`, `icon`, `route_name`, `route_path`, `component_path`, `redirect`, `hidden`, `keep_alive`, `always_show`, `title`, `params`, `affix`, `parent_id`, `uuid`, `status`, `description`, `created_time`, `updated_time`)
VALUES
-('{{ function_name }}', 2, 9999, '{{ permission_prefix }}:query', '{{ icon }}', '{{ business_name|snake_to_camel }}', '/{{ module_name }}/{{ business_name }}', '/{{ module_name }}/{{ business_name }}/index', NULL, {{ b_false }}, {{ b_true }}, {{ b_false }}, '{{ function_name }}', NULL, {{ b_false }}, {{ parent_menu_id }}, {{ set_uuid }}, '0', '{{ function_name }}菜单', NOW(), NOW());
+('{{ function_name }}', 2, 9999, '{{ permission_prefix }}:query', '{{ icon }}', '{{ business_name|snake_to_camel }}', '/{{ module_name }}/{{ business_name }}', '{{ module_name }}/{{ business_name }}/index', NULL, {{ b_false }}, {{ b_true }}, {{ b_false }}, '{{ function_name }}', NULL, {{ b_false }}, {{ parent_menu_id }}, {{ set_uuid }}, '0', '{{ function_name }}菜单', NOW(), NOW());
-- 获取父菜单ID(MySQL)
SELECT @parentId := LAST_INSERT_ID();
@@ -39,7 +39,7 @@ BEGIN
INSERT INTO {{ sys_menu }}
(name, type, {{ order_col }}, permission, icon, route_name, route_path, component_path, redirect, hidden, keep_alive, always_show, title, params, affix, parent_id, uuid, status, description, created_time, updated_time )
VALUES
-('{{ function_name }}', 2, 9999, '{{ permission_prefix }}:query', '{{ icon }}', '{{ business_name|snake_to_camel }}', '/{{ module_name }}/{{ business_name }}', '/{{ module_name }}/{{ business_name }}/index', NULL, {{ b_false }}, {{ b_true }}, {{ b_false }}, '{{ function_name }}', NULL, {{ b_false }}, {{ parent_menu_id }}, {{ set_uuid }}, '0', '{{ function_name }}菜单', NOW(), NOW())
+('{{ function_name }}', 2, 9999, '{{ permission_prefix }}:query', '{{ icon }}', '{{ business_name|snake_to_camel }}', '/{{ module_name }}/{{ business_name }}', '{{ module_name }}/{{ business_name }}/index', NULL, {{ b_false }}, {{ b_true }}, {{ b_false }}, '{{ function_name }}', NULL, {{ b_false }}, {{ parent_menu_id }}, {{ set_uuid }}, '0', '{{ function_name }}菜单', NOW(), NOW())
RETURNING id INTO parent_id;
-- 按钮权限(类型=3:按钮/权限)
diff --git a/backend/app/api/v1/module_generator/gencode/templates/ts/api.ts.j2 b/backend/app/api/v1/module_generator/gencode/templates/ts/api.ts.j2
index 14520ce2..57b28ce3 100644
--- a/backend/app/api/v1/module_generator/gencode/templates/ts/api.ts.j2
+++ b/backend/app/api/v1/module_generator/gencode/templates/ts/api.ts.j2
@@ -1,6 +1,6 @@
import request from "@/utils/request";
-const API_PATH = "/{{ module_name }}/{{ business_name|lower }}";
+const API_PATH = "/{{ package_name }}/{{ business_name|lower }}";
const {{ class_name }}API = {
// 列表查询
@@ -95,7 +95,7 @@ export default {{ class_name }}API;
// 列表查询参数
export interface {{ class_name }}PageQuery extends PageQuery {
{% for column in columns %}
- {% if column.is_query and column.column != "BETWEEN" %}
+ {% if column.is_query and column.column != "BETWEEN" and column.column_name not in ['created_time', 'updated_time'] %}
{{ column.column_name }}?: {{
'string' if ('status' in (column.python_field|lower)) or (column.html_type == 'radio')
else 'number' if column.is_pk == '1'
@@ -110,7 +110,6 @@ export interface {{ class_name }}PageQuery extends PageQuery {
// 列表展示项
export interface {{ class_name }}Table extends BaseType{
- index?: number;
{% for column in columns %}
{% if column.column_name not in ['id', 'uuid', 'status', 'description', 'created_time', 'updated_time'] %}
{{ column.column_name }}?: {{
diff --git a/backend/app/api/v1/module_generator/gencode/templates/vue/index.vue.j2 b/backend/app/api/v1/module_generator/gencode/templates/vue/index.vue.j2
index f23f50ab..2b3b4860 100644
--- a/backend/app/api/v1/module_generator/gencode/templates/vue/index.vue.j2
+++ b/backend/app/api/v1/module_generator/gencode/templates/vue/index.vue.j2
@@ -16,7 +16,43 @@
{% set column_comment = column.column_comment if column.column_comment else '' %}
{% set parentheseIndex = column_comment.find("(") %}
{% set comment = column_comment[:parentheseIndex] if parentheseIndex != -1 else column_comment %}
- {% if column.html_type == "input" %}
+ {% if column.column_name == "status" %}
+
+
+
+
+
+
+ {% elif column.column_name == "created_id"%}
+
+
+
+ {% elif column.column_name == "updated_id"%}
+
+
+
+ {% elif column.column_name == "created_time"%}
+
+
+
+ {% elif column.column_name == "updated_time"%}
+
+
+
+ {% elif column.html_type == "input" %}
@@ -39,38 +75,6 @@
{% endif %}
{% endif %}
{% endfor %}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
批量启用
-
+
批量停用
@@ -344,24 +348,27 @@
{% for column in columns %}
- {% set python_field = column.column_name %}
{% set column_comment = column.column_comment if column.column_comment else '' %}
{% set parentheseIndex = column_comment.find("(") %}
{% set comment = column_comment[:parentheseIndex] if parentheseIndex != -1 else column_comment %}
- {% if column.python_field == 'status' %}
+ {% if column.column_name == 'status' %}
{{ '{{' }} detailFormData.status == '0' ? "启用" : "停用" {{ '}}' }}
- {% elif column.python_field == 'created_id' %}
+ {% elif column.column_name == 'created_id' %}
{{ '{{' }} detailFormData.created_by?.name {{ '}}' }}
- {% elif column.python_field == 'updated_id' %}
+ {% elif column.column_name == 'updated_id' %}
{{ '{{' }} detailFormData.updated_by?.name {{ '}}' }}
+ {% else %}
+
+ {{ '{{' }} detailFormData.{{ column.column_name }} {{ '}}' }}
+
{% endif %}
{% endfor %}
@@ -377,14 +384,25 @@
{% set parentheseIndex = column_comment.find("(") %}
{% set comment = column_comment[:parentheseIndex] if parentheseIndex != -1 else column_comment %}
{% set required = 'true' if column.is_nullable == '1' else 'false' %}
- {% if column.column_name not in ['uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
+ {% if column.column_name not in ['id', 'uuid', 'created_time', 'updated_time', 'created_id', 'updated_id'] %}
{% if column.column_name == "status" %}
- 启用
- 停用
+ 启用
+ 停用
+ {% elif column.column_name == "description" %}
+
+
+
{% elif column.html_type == "input" %}
diff --git a/backend/app/api/v1/module_generator/gencode/tools/gen_util.py b/backend/app/api/v1/module_generator/gencode/tools/gen_util.py
index 769f8eaa..086411a8 100644
--- a/backend/app/api/v1/module_generator/gencode/tools/gen_util.py
+++ b/backend/app/api/v1/module_generator/gencode/tools/gen_util.py
@@ -24,8 +24,8 @@ class GenUtils:
"""
# 只有当字段为None时才设置默认值
gen_table.class_name = cls.convert_class_name(gen_table.table_name or "")
- gen_table.package_name = 'module_gencode'
- gen_table.module_name = gen_table.package_name.split('.')[-1]
+ gen_table.package_name = 'gencode'
+ gen_table.module_name = f'module_{gen_table.package_name}'
gen_table.business_name = gen_table.table_name
gen_table.function_name = re.sub(r'(?:表|测试)', '', gen_table.table_comment or "")
diff --git a/backend/env/.env.dev b/backend/env/.env.dev
index 94987f52..b01783fb 100644
--- a/backend/env/.env.dev
+++ b/backend/env/.env.dev
@@ -26,7 +26,7 @@ DATABASE_TYPE = "postgres" # mysql、postgres
# 数据库配置
DATABASE_HOST = "localhost"
-DATABASE_PORT = 5432 # MySQL:3006 PostgreSQL:5432
+DATABASE_PORT = 5432 # MySQL:3306 PostgreSQL:5432
DATABASE_USER = "tao" # mysql:root, postgresql:tao
DATABASE_PASSWORD = "ServBay.dev"
DATABASE_NAME = "fastapiadmin"
diff --git a/frontend/src/views/module_generator/gencode/index.vue b/frontend/src/views/module_generator/gencode/index.vue
index dd4fb2c7..4d81552c 100644
--- a/frontend/src/views/module_generator/gencode/index.vue
+++ b/frontend/src/views/module_generator/gencode/index.vue
@@ -516,9 +516,6 @@
backend/app/api/v1/{{ info.module_name }}/{{ info.business_name }}/model.py
-
- backend/app/api/v1/{{ info.module_name }}/{{ info.business_name }}/param.py
-
backend/app/api/v1/{{ info.module_name }}/{{ info.business_name }}/schema.py