diff --git a/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py b/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py
index 28604c8..94dbc02 100644
--- a/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py
+++ b/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py
@@ -84,7 +84,7 @@ class MetaSecurityDao:
return row_list
@classmethod
- async def get_api_col_list(cls, db: AsyncSession, dbRCode: str,dbTname:str,objType:str,objValue:str):
+ async def get_api_col_list(cls, db: AsyncSession, dbRCode: str,dbSName: str,dbTname:str,objType:str,objValue:str):
colList = (
await db.execute(
select(MetaSecurityCol)
@@ -92,6 +92,7 @@ class MetaSecurityDao:
(MetaSecurityCol.isStop == 0) &
(MetaSecurityCol.dbRName == dbRCode) &
(MetaSecurityCol.obj_type == objType) &
+ (MetaSecurityCol.dbSName == dbSName) &
(MetaSecurityCol.dbTName == dbTname) &
(MetaSecurityCol.obj_value == objValue)
)
@@ -99,7 +100,7 @@ class MetaSecurityDao:
).scalars().all()
return colList
@classmethod
- async def get_api_row_list(cls, db: AsyncSession, dbRCode: str,dbTname:str,objType:str,objValue:str):
+ async def get_api_row_list(cls, db: AsyncSession, dbRCode: str,dbSName: str,dbTname:str,objType:str,objValue:str):
colList = (
await db.execute(
select(MetaSecurityRow)
@@ -107,6 +108,7 @@ class MetaSecurityDao:
(MetaSecurityRow.isStop == 0) &
(MetaSecurityRow.dbRName == dbRCode) &
(MetaSecurityRow.obj_type == objType) &
+ (MetaSecurityRow.dbSName == dbSName) &
(MetaSecurityRow.dbTName == dbTname) &
(MetaSecurityRow.obj_value == objValue)
)
diff --git a/vue-fastapi-backend/module_admin/entity/do/datastd_do.py b/vue-fastapi-backend/module_admin/entity/do/datastd_do.py
index 8c92b18..48ed6fd 100644
--- a/vue-fastapi-backend/module_admin/entity/do/datastd_do.py
+++ b/vue-fastapi-backend/module_admin/entity/do/datastd_do.py
@@ -100,6 +100,8 @@ class DataStdMain(Base):
std_code = Column(String(50), default=None, comment='标准英文名')
std_name = Column(String(200), default=None, comment='标准中文名')
std_type = Column(String(1), default=None, comment='标准类型(0:基础数据 1:指标数据)')
+ securityLevel = Column(String(1), default=None, comment='安全等级')
+ sourceSystem = Column(String(50), default=None, comment='来源系统')
sys_name = Column(String(50), default=None, comment='归属系统')
sys_id = Column(Integer, default=None, comment='归属系统Id')
std_menu = Column(String(200), default=None, comment='标准业务定义')
diff --git a/vue-fastapi-backend/module_admin/entity/vo/datastd_vo.py b/vue-fastapi-backend/module_admin/entity/vo/datastd_vo.py
index 2d59c9c..7f4c609 100644
--- a/vue-fastapi-backend/module_admin/entity/vo/datastd_vo.py
+++ b/vue-fastapi-backend/module_admin/entity/vo/datastd_vo.py
@@ -102,6 +102,8 @@ class DataStdMainModel(BaseModel):
std_code: Optional[str] = Field(default=None, description='标准英文名')
std_name: Optional[str] = Field(default=None, description='标准中文名')
std_type: Optional[str] = Field(default=None, description='标准类型(0:基础数据 1:指标数据)')
+ securityLevel: Optional[str] = Field(default=None, description='安全等级')
+ sourceSystem: Optional[str] = Field(default=None, description='来源系统')
sys_name: Optional[str] = Field(default=None, description='归属系统')
sys_id: Optional[int] = Field(default=None, description='归属系统Id')
std_menu: Optional[str] = Field(default=None, description='标准业务定义')
diff --git a/vue-fastapi-backend/module_admin/service/metasecurity_service.py b/vue-fastapi-backend/module_admin/service/metasecurity_service.py
index 28a2305..cb9997d 100644
--- a/vue-fastapi-backend/module_admin/service/metasecurity_service.py
+++ b/vue-fastapi-backend/module_admin/service/metasecurity_service.py
@@ -304,7 +304,9 @@ class MetaSecurityService:
# dbConnent= cls.get_db_engine("postgresql",dataParams])
dbConnent= cls.get_db_engine(dsDataResource["type"],dsDataResource["connectionParams"])
# await test_connection(dbConnent)
- #3.执行原始sql
+ #3获取sql中涉及的表名
+ sqlScheamAndTable =await cls.get_tables_from_sql(page_object.sqlStr)
+ #4.执行原始sql
result = await cls.execute_sql(dbConnent, page_object.sqlStr,"原始")
if 3 in role_id_list:
resultDict={
@@ -314,16 +316,15 @@ class MetaSecurityService:
}
return resultDict
- #4.获取sql中涉及的表名
- sqlTableNames =await cls.get_tables_from_sql(page_object.sqlStr)
+
#5.根据表名获取数据库中的字段名
- table_columns = await cls.get_columns_from_tables(dbConnent, sqlTableNames,dsDataResource["type"],)
+ table_columns = await cls.get_columns_from_tables(dbConnent, sqlScheamAndTable,dsDataResource["type"],)
#6.查询用户及该用户角色下的所有行列配置
tablesRowCol = {}
# 遍历每个表名,获取对应的配置
- for table_name in sqlTableNames:
+ for table_name in sqlScheamAndTable:
table_configs = await get_table_configs(query_db, page_object, user, role_id_list, table_name)
tablesRowCol[table_name] = table_configs
@@ -403,15 +404,64 @@ class MetaSecurityService:
return result_dict
except SQLAlchemyError as e:
raise RuntimeError(f"{sql_type}执行 SQL 查询时发生错误: {e}")
- async def get_tables_from_sql(sql_query:str):
- table_pattern = r"(FROM|JOIN|INTO|UPDATE)\s+([a-zA-Z0-9_]+(?:\.[a-zA-Z0-9_]+))"
-
- table_matches = re.findall(table_pattern, sql_query, re.IGNORECASE)
-
- table_names = [match[1] for match in table_matches]
- table_names = [match[1].split('.')[-1] for match in table_matches] # `split('.')[-1]` 取最后一部分,即表名
- return table_names
+ # async def get_tables_from_sql(sql_query: str):
+ # """
+ # 解析 SQL 查询,提取所有 Schema 和 Table 名称,并确保表名包含模式名(schema.table)。
+
+ # :param sql_query: SQL 查询字符串
+ # :return: {'schemas': [...], 'table_names': [...]}
+ # :raises ServiceException: 如果 SQL 未使用 schema.table 结构,则抛出异常
+ # """
+ # # ✅ 改进正则:支持 `FROM a.o, b.x JOIN c.y`
+ # table_section_pattern = r"(?i)(?:FROM|JOIN|INTO|UPDATE)\s+([\w\.\s,]+)"
+
+ # table_sections = re.findall(table_section_pattern, sql_query, re.DOTALL)
+
+ # if not table_sections:
+ # raise ServiceException(data='', message='SQL 解析失败,未找到表名')
+ # # 解析多个表(用 `,` 和 `JOIN` 拆分)
+ # for section in table_sections:
+ # tables = re.split(r"\s*,\s*|\s+JOIN\s+", section, flags=re.IGNORECASE)
+ # for table in tables:
+ # table = table.strip().split()[0] # 取 `schema.table`,忽略别名
+ # if "." not in table:
+ # raise ServiceException(
+ # data='',
+ # message=f"SQL 中的表名必须携带模式名(schema.table),但发现了无模式的表:{table}"
+ # )
+ # return table_sections
+ async def get_tables_from_sql(sql_query: str):
+ """
+ 解析 SQL 查询,提取所有 Schema 和 Table 名称,并确保表名包含模式名(schema.table)。
+
+ :param sql_query: SQL 查询字符串
+ :return: {'schemas': [...], 'table_names': [...]}
+ :raises ServiceException: 如果 SQL 未使用 schema.table 结构,则抛出异常
+ """
+ # ✅ 改进正则,支持 `FROM ... JOIN ...`,并适配换行符
+ table_section_pattern = r"(?i)(?:FROM|JOIN|INTO|UPDATE)\s+([\w\.\s,]+)"
+
+ # 允许 `.` 匹配换行符,确保提取完整的 `FROM` 和 `JOIN` 语句
+ table_sections = re.findall(table_section_pattern, sql_query, re.DOTALL)
+
+ if not table_sections:
+ raise ServiceException(data='', message='SQL 解析失败,未找到表名')
+
+ table_names = set() # 使用集合去重
+ for section in table_sections:
+ # 按 `,` 或 `JOIN` 拆分,提取表名
+ tables = re.split(r"\s*,\s*|\s+JOIN\s+", section.strip(), flags=re.IGNORECASE)
+ for table in tables:
+ table = table.strip().split()[0] # 取 `schema.table`,忽略别名
+ if "." not in table:
+ raise ServiceException(
+ data='',
+ message=f"SQL 中的表名必须携带模式名(schema.table),但发现了无模式的表:{table}"
+ )
+ table_names.add(table)
+
+ return list(table_names)
@classmethod
async def get_columns_from_tables(cls, dbConnent, table_names, db_type: str):
@@ -419,12 +469,21 @@ class MetaSecurityService:
columns = {}
query=""
for table_name in table_names:
+ schema, table = table_name.split(".")
if db_type.lower() == "postgresql":
- # PostgreSQL: 使用 information_schema.columns 查询字段
- query= f"SELECT column_name FROM information_schema.columns WHERE table_name ='{table_name}'"
+ # PostgreSQL: 查询指定 schema 下的表字段
+ query = f"""
+ SELECT column_name
+ FROM information_schema.columns
+ WHERE table_schema = '{schema}' AND table_name = '{table}'
+ """
elif db_type.lower() == "mysql":
- # MySQL: 使用 INFORMATION_SCHEMA.COLUMNS 查询字段
- query= f"SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME ='{table_name}'"
+ # MySQL: 直接查询表字段(MySQL 没有 schema 的概念)
+ query = f"""
+ SELECT COLUMN_NAME
+ FROM INFORMATION_SCHEMA.COLUMNS
+ WHERE TABLE_NAME = '{table}'
+ """
else:
raise ValueError(f"暂不支持数据库类型: {db_type}")
@@ -447,29 +506,32 @@ def convert_decimal(obj):
return [convert_decimal(item) for item in obj]
return obj # 返回非 Decimal、dict 或 list 的值
async def get_table_configs(query_db, page_object, user, role_id_list, table_name):
+ parts = table_name.split(".")
+ schema, table = parts
# 获取用户的列配置
user_col_list = await MetaSecurityDao.get_api_col_list(
- query_db, page_object.dbRCode, table_name, '0', user[0].user_id
+ query_db, page_object.dbRCode, schema,table, '0', user[0].user_id
)
-
+
+
# 获取角色的列配置
role_col_list = []
for role_id in role_id_list:
role_cols = await MetaSecurityDao.get_api_col_list(
- query_db, page_object.dbRCode, table_name, '1', role_id
+ query_db, page_object.dbRCode, schema,table, '1', role_id
)
role_col_list.extend(role_cols) # 将每个角色的列配置合并到列表中
# 获取用户的行配置
user_row_list = await MetaSecurityDao.get_api_row_list(
- query_db, page_object.dbRCode, table_name, '0', user[0].user_id
+ query_db, page_object.dbRCode, schema,table, '0', user[0].user_id
)
# 获取角色的行配置
role_row_list = []
for role_id in role_id_list:
role_rows = await MetaSecurityDao.get_api_row_list(
- query_db, page_object.dbRCode, table_name, '1', role_id
+ query_db, page_object.dbRCode,schema,table, '1', role_id
)
role_row_list.extend(role_rows) # 将每个角色的行配置合并到列表中
isHave = any([
@@ -567,7 +629,7 @@ async def generate_sql(tablesRowCol:dict, table_columns:dict):
tab_col_value=row.ctrl_value.split(".")
if len(tab_col_value) != 2:
raise RuntimeError(f"{row.dbCName}字段控制类型为表字段,未维护正确的值")
- select_rows[row.dbCName] = f"{row.dbCName} in (select {tab_col_value[1]} from {tab_col_value[0]})"
+ select_rows[row.dbCName] = f"{row.dbCName} in (select {tab_col_value[1]} from {row.dbSName}.{tab_col_value[0]} where user_id = '1')"
# 处理用户行配置
for row in config["user_row_list"]:
# 仅仅对固定值有效,不加行限制
@@ -587,7 +649,7 @@ async def generate_sql(tablesRowCol:dict, table_columns:dict):
tab_col_value=row.ctrl_value.split(".")
if len(tab_col_value) != 2:
raise RuntimeError(f"{row.dbCName}字段控制类型为表字段,未维护正确的值")
- select_rows[row.dbCName] = f"{row.dbCName} in (select {tab_col_value[1]} from {tab_col_value[0]})"
+ select_rows[row.dbCName] = f"{row.dbCName} in (select {tab_col_value[1]} from {row.dbSName}.{tab_col_value[0]} where user_id = '1')"
if select_rows.values():
where_conditions = " AND ".join(select_rows.values())
if where_conditions:
diff --git a/vue-fastapi-frontend/src/views/datastd/main/components/AddEditForm.vue b/vue-fastapi-frontend/src/views/datastd/main/components/AddEditForm.vue
index 7742ef0..5d48a94 100644
--- a/vue-fastapi-frontend/src/views/datastd/main/components/AddEditForm.vue
+++ b/vue-fastapi-frontend/src/views/datastd/main/components/AddEditForm.vue
@@ -39,6 +39,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -514,6 +518,8 @@ const handleAdd = () => {
bussUser: "",
techDeptId: "",
techUser: "",
+ securityLevel:"",
+ sourceSystem:""
};
// 清空选中的数据