From a8c731f92602daf16c2d48905b273305d6041146 Mon Sep 17 00:00:00 2001 From: "si@aidatagov.com" Date: Sun, 7 Dec 2025 21:20:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/metasecurity_controller.py | 15 ++ .../module_admin/dao/metaSecurity_dao.py | 36 +++- .../service/metasecurity_service.py | 14 ++ .../src/api/meta/metasercurity.js | 7 +- .../meta/metasercurity/MetaSecurityCol.vue | 162 +++++++++++++---- .../meta/metasercurity/MetaSecurityRow.vue | 166 +++++++++++++----- 6 files changed, 318 insertions(+), 82 deletions(-) diff --git a/vue-fastapi-backend/module_admin/controller/metasecurity_controller.py b/vue-fastapi-backend/module_admin/controller/metasecurity_controller.py index ccb9af1..fd188b6 100644 --- a/vue-fastapi-backend/module_admin/controller/metasecurity_controller.py +++ b/vue-fastapi-backend/module_admin/controller/metasecurity_controller.py @@ -41,6 +41,21 @@ async def get_meta_security_row_list( row_page_query_result = await MetaSecurityService.get_meta_security_row_list_services(query_db, row_page_query, is_page=True) logger.info('获取行配置列表成功') return ResponseUtil.success(model_content=row_page_query_result) +@metaSecurityController.get( + '/mdlNamelist/{ssys_id}', + dependencies=[Depends(CheckUserInterfaceAuth('meta:metasecurity:row:list'))] +) +async def get_meta_mdlName_list( + ssys_id: int , + query_db: AsyncSession = Depends(get_db), +): + """ + 获取指定系统下的模式名(schema)列表 + """ + result = await MetaSecurityService.get_meta_mdlName_list_services(query_db, ssys_id) + logger.info("获取系统模式名列表成功") + return ResponseUtil.success(data=result) + @metaSecurityController.get( '/row/{row_id}', response_model=MetaSecurityRowModel, dependencies=[Depends(CheckUserInterfaceAuth('meta:metasecurity:row:list'))] ) diff --git a/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py b/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py index 94dbc02..4e291c6 100644 --- a/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py +++ b/vue-fastapi-backend/module_admin/dao/metaSecurity_dao.py @@ -1,10 +1,9 @@ -from sqlalchemy import delete, select, update, desc +from sqlalchemy import delete, func, select, update, desc from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.metasecurity_do import MetaSecurityCol, MetaSecurityRow from module_admin.entity.vo.metasecurity_vo import MetaSecurityColModel, MetaSecurityRowModel from utils.page_util import PageUtil - - +from module_admin.entity.do.meta_do import MetadataExtractInfo, MetadataSuppInfo class MetaSecurityDao: """ 数据源安全管理模块数据库操作层 @@ -82,6 +81,37 @@ class MetaSecurityDao: db, query, query_object.page_num, query_object.page_size, is_page ) return row_list + @classmethod + async def get_schema_by_system(cls, db: AsyncSession, ssys_id: int): + """ + 获取指定系统下的模式名(schema),从两个表取合集(去重) + """ + if not ssys_id: + raise ValueError("系统名(ssys_id)为必填参数") + + # 第一个表 + q1 = ( + select(MetadataExtractInfo.mdl_name.label("schema")) + .where(MetadataExtractInfo.ssys_id == ssys_id) + ) + + # 第二个表 + q2 = ( + select(MetadataSuppInfo.mdl_name.label("schema")) + .where(MetadataSuppInfo.ssys_id == ssys_id) + ) + + # UNION ALL + DISTINCT(正确写法) + union_sub = q1.union_all(q2).subquery() + + union_query = ( + select(func.distinct(union_sub.c.schema).label("schema")) + .order_by(union_sub.c.schema) + ) + + result = await db.execute(union_query) + return [row.schema for row in result.fetchall() if row.schema] + @classmethod async def get_api_col_list(cls, db: AsyncSession, dbRCode: str,dbSName: str,dbTname:str,objType:str,objValue:str): diff --git a/vue-fastapi-backend/module_admin/service/metasecurity_service.py b/vue-fastapi-backend/module_admin/service/metasecurity_service.py index 93c90a0..ce2c741 100644 --- a/vue-fastapi-backend/module_admin/service/metasecurity_service.py +++ b/vue-fastapi-backend/module_admin/service/metasecurity_service.py @@ -54,6 +54,20 @@ class MetaSecurityService: """ row_list_result = await MetaSecurityDao.get_meta_security_row_list(query_db, query_object, is_page) return row_list_result + @classmethod + async def get_meta_mdlName_list_services( + cls, query_db: AsyncSession, ssys_id: int + ): + """ + 获取行配置列表信息service + + :param query_db: orm对象 + :param query_object: 查询参数对象 + :param is_page: 是否开启分页 + :return: 行配置列表信息对象 + """ + row_list_result = await MetaSecurityDao.get_schema_by_system(query_db, ssys_id) + return row_list_result @classmethod async def get_meta_security_col_by_id_services(cls, query_db: AsyncSession, colId: str): diff --git a/vue-fastapi-frontend/src/api/meta/metasercurity.js b/vue-fastapi-frontend/src/api/meta/metasercurity.js index f4a61cd..47d8952 100644 --- a/vue-fastapi-frontend/src/api/meta/metasercurity.js +++ b/vue-fastapi-frontend/src/api/meta/metasercurity.js @@ -26,7 +26,12 @@ export function getMetaSecurityCol(colId) { method: 'get' }) } - +export function getMetaMdlNameList(ssysId) { + return request({ + url: '/default-api/meta/metaSecurity/mdlNamelist/' + ssysId, + method: 'get' + }) +} // 查询行配置详情 export function getMetaSecurityRow(rowId) { return request({ diff --git a/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityCol.vue b/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityCol.vue index a8164e4..eea3529 100644 --- a/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityCol.vue +++ b/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityCol.vue @@ -174,13 +174,32 @@ - + + + + + + - + + + + + + + + + - - - - + import { ref, reactive, onMounted, toRefs } from 'vue'; -import { listMetaSecurityCol, addMetaSecurityCol,getMetaSecurityCol, updateMetaSecurityCol, deleteMetaSecurityCol } from "@/api/meta/metasercurity"; +import { listMetaSecurityCol, addMetaSecurityCol,getMetaSecurityCol, updateMetaSecurityCol, deleteMetaSecurityCol,getMetaMdlNameList } from "@/api/meta/metasercurity"; import { datasourcetree } from "@/api/meta/metatask"; import { listUser} from "@/api/system/user"; import { listRole} from "@/api/system/role"; + import { getMetaDataList, getColumnList } from "@/api/meta/metaInfo" const { proxy } = getCurrentInstance(); const { metasecurity_ctr, metasecurity_obj, metasecurity_type} = proxy.useDict("metasecurity_ctr", "metasecurity_obj", "metasecurity_type"); @@ -274,6 +292,9 @@ const queryParams = ref({ pageNum: 1, pageSize: 10 }); +const schemaList = ref([]) // 模式 +const tableList = ref([]) // 表 +const columnList = ref([]) // 字段(多选) const single = ref(true); const multiple = ref(true); const dbResoursName = ref(undefined); @@ -309,7 +330,7 @@ const form = ref({ dbRID: 0, dbSName: '', dbTName: '', - dbCName: '', + dbCName: [] , // 字段(多选) ctrlType: '', objType: '', objValue: '', @@ -355,6 +376,63 @@ const handleObjValueChange = (selectedValues) => { }; +const dataChange = async (dbRID) => { + form.value.dbRID = dbRID + + // 1) 加载模式 schema(你已有接口) + const res = await getMetaMdlNameList(dbRID) + schemaList.value = res.data + + // 清空下级 + form.value.dbSName = "" + form.value.dbTName = "" + form.value.dbCName = [] + tableList.value = [] + columnList.value = [] + const selectedItem = dbResourceOldList.value.find(item => item.id === dbRID); + if (selectedItem) { + // 如果找到对应的项,将 name 赋值给 form.value.dbRName + form.value.dbRName = selectedItem.name; + } else { + // 如果未找到,清空 form.value.dbRName + form.value.dbRName = ''; + } +} +const onSchemaChange = async (mdlName) => { + form.value.dbTName = "" + form.value.dbCName = [] + tableList.value = [] + columnList.value = [] + + if (!mdlName) return + + const queryParams = { + ssysId: form.value.dbRID, // 系统 ID + mdlName: mdlName, + pageNum: 1, + pageSize: 10000 + } + + const res = await getMetaDataList(queryParams) + tableList.value = res.data.rows.map(item => item.tabEngName) +} +const onTableChange = async (tabName) => { + form.value.dbCName = [] + columnList.value = [] + + if (!tabName) return + + const params = { + ssysId: form.value.dbRID, + mdlName: form.value.dbSName, + tabName: tabName + } + + const res = await getColumnList(params) +columnList.value = ["ALL", ...res.data.map(item => item.fldEngName)] + +} + // 获取数据列表 const getList = async () => { loading.value = true; @@ -394,18 +472,7 @@ const getRoleName = (objValue) => { }); return names.join(', '); }; -function dataChange(data) { - // 从 dbResourceOldList 中查找对应的 name - const selectedItem = dbResourceOldList.value.find(item => item.id === data); - if (selectedItem) { - // 如果找到对应的项,将 name 赋值给 form.value.dbRName - form.value.dbRName = selectedItem.name; - } else { - // 如果未找到,清空 form.value.dbRName - form.value.dbRName = ''; - } -} // 翻页 const handlePagination = (pageNum, pageSize) => { queryParams.pageNum = pageNum; @@ -453,8 +520,19 @@ const getDeptTree = async () => { const handleEdit = (row) => { reset(); const colId = row.colId || ids.value; + getMetaSecurityCol(colId).then(response => { - form.value = response.data; + const data = response.data; + + // ⭐ 回显字段多选:字符串 → 数组 + if (data.dbCName && typeof data.dbCName === 'string') { + data.dbCName = data.dbCName.split(','); + } else if (!data.dbCName) { + data.dbCName = []; + } + + form.value = data; + dialogVisible.value = true; dialogTitle.value = "编辑列配置"; }); @@ -464,25 +542,35 @@ const handleEdit = (row) => { function handleSave() { proxy.$refs["formRef"].validate(valid => { - if (valid) { - if (form.value.colId != undefined&&form.value.colId !="") { - updateMetaSecurityCol(form.value).then(response => { - proxy.$modal.msgSuccess("修改成功"); - dialogVisible.value = false; - getList(); - }); - } else { - const submitData = { ...form.value }; - submitData.objValue = submitData.objValue.join(','); - addMetaSecurityCol(submitData).then(response => { - proxy.$modal.msgSuccess("新增成功"); - dialogVisible.value = false; - getList(); - }); - } + if (!valid) return; + + // 克隆一份数据,避免直接修改 form + const submitData = { ...form.value }; + + // 多选字段转换为逗号字符串 + if (Array.isArray(submitData.dbCName)) { + submitData.dbCName = submitData.dbCName.join(','); + } + if (Array.isArray(submitData.objValue)) { + submitData.objValue = submitData.objValue.join(','); + } + // 判断是新增还是修改 + if (submitData.colId) { + updateMetaSecurityCol(submitData).then(() => { + proxy.$modal.msgSuccess("修改成功"); + dialogVisible.value = false; + getList(); + }); + } else { + addMetaSecurityCol(submitData).then(() => { + proxy.$modal.msgSuccess("新增成功"); + dialogVisible.value = false; + getList(); + }); } }); } + /** 表单重置 */ function reset() { form.value = { @@ -491,7 +579,7 @@ function reset() { dbRID: undefined, dbSName: '', dbTName: '', - dbCName: '', + dbCName: [], generateType: '', ctrlType: '', objType: '', diff --git a/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityRow.vue b/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityRow.vue index 3bde4ec..a081fd7 100644 --- a/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityRow.vue +++ b/vue-fastapi-frontend/src/views/meta/metasercurity/MetaSecurityRow.vue @@ -164,15 +164,29 @@ > - - - - - - - - - + + + + + + + + + + + + + + + + + import { ref, reactive, onMounted, toRefs } from 'vue'; -import { listMetaSecurityRow, addMetaSecurityRow,getMetaSecurityRow, updateMetaSecurityRow, deleteMetaSecurityRow } from "@/api/meta/metasercurity"; +import { listMetaSecurityRow, addMetaSecurityRow,getMetaSecurityRow, updateMetaSecurityRow, deleteMetaSecurityRow,getMetaMdlNameList } from "@/api/meta/metasercurity"; const { proxy } = getCurrentInstance(); const { metasecurity_ctr, metasecurity_obj, metasecurity_type} = proxy.useDict("metasecurity_ctr", "metasecurity_obj", "metasecurity_type"); import { datasourcetree } from "@/api/meta/metatask"; import { listUser} from "@/api/system/user"; import { listRole} from "@/api/system/role"; + import { getMetaDataList, getColumnList } from "@/api/meta/metaInfo" + const queryParams = ref({ dbCName: '', dbTName: '', @@ -250,18 +266,9 @@ const queryParams = ref({ }); const single = ref(true); const multiple = ref(true); -function dataChange(data) { - -// 从 dbResourceOldList 中查找对应的 name -const selectedItem = dbResourceOldList.value.find(item => item.id === data); -if (selectedItem) { -// 如果找到对应的项,将 name 赋值给 form.value.dbRName -form.value.dbRName = selectedItem.name; -} else { -// 如果未找到,清空 form.value.dbRName -form.value.dbRName = ''; -} -} + const schemaList = ref([]) // 模式 +const tableList = ref([]) // 表 +const columnList = ref([]) // 字段(多选) const dbResourceOptions = ref(undefined); const form = ref({ dbRName: '', // 连接 @@ -295,6 +302,62 @@ const handleObjValueChange = (selectedValues) => { }; +const dataChange = async (dbRID) => { + form.value.dbRID = dbRID + + // 1) 加载模式 schema(你已有接口) + const res = await getMetaMdlNameList(dbRID) + schemaList.value = res.data + + // 清空下级 + form.value.dbSName = "" + form.value.dbTName = "" + form.value.dbCName = [] + tableList.value = [] + columnList.value = [] + const selectedItem = dbResourceOldList.value.find(item => item.id === dbRID); + if (selectedItem) { + // 如果找到对应的项,将 name 赋值给 form.value.dbRName + form.value.dbRName = selectedItem.name; + } else { + // 如果未找到,清空 form.value.dbRName + form.value.dbRName = ''; + } +} +const onSchemaChange = async (mdlName) => { + form.value.dbTName = "" + form.value.dbCName = [] + tableList.value = [] + columnList.value = [] + + if (!mdlName) return + + const queryParams = { + ssysId: form.value.dbRID, // 系统 ID + mdlName: mdlName, + pageNum: 1, + pageSize: 10000 + } + + const res = await getMetaDataList(queryParams) + tableList.value = res.data.rows.map(item => item.tabEngName) +} +const onTableChange = async (tabName) => { + form.value.dbCName = [] + columnList.value = [] + + if (!tabName) return + + const params = { + ssysId: form.value.dbRID, + mdlName: form.value.dbSName, + tabName: tabName + } + + const res = await getColumnList(params) +columnList.value = ["ALL", ...res.data.map(item => item.fldEngName)] + +} /** 重置按钮操作 */ function resetQuery() { @@ -405,39 +468,60 @@ const handlePagination = (pageNum, pageSize) => { }; // 打开编辑对话框 + const handleEdit = (row) => { reset(); const rowId = row.rowId || ids.value; + getMetaSecurityRow(rowId).then(response => { - form.value = response.data; + const data = response.data; + + // ⭐ 回显字段多选:字符串 → 数组 + if (data.dbCName && typeof data.dbCName === 'string') { + data.dbCName = data.dbCName.split(','); + } else if (!data.dbCName) { + data.dbCName = []; + } + + form.value = data; + dialogVisible.value = true; dialogTitle.value = "编辑行配置"; }); }; // 保存数据 - function handleSave() { proxy.$refs["formRef"].validate(valid => { - if (valid) { - if (form.value.rowId != undefined&&form.value.rowId !="") { - updateMetaSecurityRow(form.value).then(response => { - proxy.$modal.msgSuccess("修改成功"); - dialogVisible.value = false; - getList(); - }); - } else { - const submitData = { ...form.value }; - submitData.objValue = submitData.objValue.join(','); - addMetaSecurityRow(submitData).then(response => { - proxy.$modal.msgSuccess("新增成功"); - dialogVisible.value = false; - getList(); - }); - } + if (!valid) return; + + // 克隆一份数据,避免直接修改 form + const submitData = { ...form.value }; + + // 多选字段转换为逗号字符串 + if (Array.isArray(submitData.dbCName)) { + submitData.dbCName = submitData.dbCName.join(','); + } + if (Array.isArray(submitData.objValue)) { + submitData.objValue = submitData.objValue.join(','); + } + // 判断是新增还是修改 + if (submitData.colId) { + updateMetaSecurityRow(submitData).then(() => { + proxy.$modal.msgSuccess("修改成功"); + dialogVisible.value = false; + getList(); + }); + } else { + addMetaSecurityRow(submitData).then(() => { + proxy.$modal.msgSuccess("新增成功"); + dialogVisible.value = false; + getList(); + }); } }); } + /** 表单重置 */ function reset() { form.value = { @@ -497,7 +581,7 @@ const getRoleName = (objValue) => { const handleCancel = () => { dialogVisible.value = false; form.value.rowId = ''; - form.value.dbCName = ''; + form.value.dbCName = []; form.value.ctrlType = ''; form.value.ctrl_value = ''; form.value.isStop = false;