diff --git a/vue-fastapi-backend/module_admin/controller/data_asset_controller.py b/vue-fastapi-backend/module_admin/controller/data_asset_controller.py
index cbece15..9175392 100644
--- a/vue-fastapi-backend/module_admin/controller/data_asset_controller.py
+++ b/vue-fastapi-backend/module_admin/controller/data_asset_controller.py
@@ -212,6 +212,30 @@ async def add_dataast_appr(
return ResponseUtil.success(msg=add_dataast_result.message)
+@dataAssetController.post('/delastappr')
+@Log(title='数据资产删除申请', business_type=BusinessType.DELETE)
+async def delete_dataast_appr(
+ request: Request,
+ delete_dataasts: DataAstApprBatchModel,
+ query_db: AsyncSession = Depends(get_db),
+ current_user: CurrentUserModel = Depends(LoginService.get_current_user),
+):
+ now = datetime.now()
+ for delete_dataast in delete_dataasts.assetItems:
+ delete_dataast.upd_prsn = current_user.user.user_name
+ delete_dataast.upd_time = now
+ if not delete_dataast.create_by:
+ delete_dataast.create_by = current_user.user.user_name
+ if not delete_dataast.create_time:
+ delete_dataast.create_time = now
+
+ delete_dataast_result = await DataAstService.delete_dataasts_appr(
+ query_db, delete_dataasts, current_user.user.user_name
+ )
+ logger.info(delete_dataast_result.message)
+ return ResponseUtil.success(msg=delete_dataast_result.message)
+
+
@dataAssetController.get('/listastappr', response_model=PageResponseModel
)
async def get_ast_main_appr_list(
@@ -221,4 +245,4 @@ async def get_ast_main_appr_list(
):
main_page_query_result = await DataAstService.get_ast_main_appr_list(query_db, flowId, is_page=True)
logger.info('获取数据标准列表成功')
- return ResponseUtil.success(data=main_page_query_result)
\ No newline at end of file
+ return ResponseUtil.success(data=main_page_query_result)
diff --git a/vue-fastapi-backend/module_admin/dao/data_asset_dao.py b/vue-fastapi-backend/module_admin/dao/data_asset_dao.py
index 6353ccd..d88ea68 100644
--- a/vue-fastapi-backend/module_admin/dao/data_asset_dao.py
+++ b/vue-fastapi-backend/module_admin/dao/data_asset_dao.py
@@ -84,7 +84,11 @@ class DataAssetDao:
:return: 数据资产信息对象
"""
data_asset = (
- await db.execute(select(DataAssetInfoAppr).where(DataAssetInfoAppr.ast_no == ast_no))
+ await db.execute(
+ select(DataAssetInfoAppr)
+ .where(DataAssetInfoAppr.ast_no == ast_no)
+ .order_by(DataAssetInfoAppr.create_time.desc())
+ )
).scalars().first()
return data_asset
@@ -220,4 +224,4 @@ class DataAssetDao:
# 分页查询
result = await PageUtil.paginate(db, query, page_num, page_size, is_page)
- return result
\ No newline at end of file
+ return result
diff --git a/vue-fastapi-backend/module_admin/dao/dataast_dao.py b/vue-fastapi-backend/module_admin/dao/dataast_dao.py
index 2dbdb05..69f8b6f 100644
--- a/vue-fastapi-backend/module_admin/dao/dataast_dao.py
+++ b/vue-fastapi-backend/module_admin/dao/dataast_dao.py
@@ -125,6 +125,11 @@ class DataAstDao:
await db.rollback()
raise e
+ @classmethod
+ async def delete_dataast_data_by_ast_no(cls, db: AsyncSession, ast_no: int):
+ await db.execute(delete(DataAssetInfo).where(DataAssetInfo.ast_no == ast_no))
+ await db.flush()
+
@classmethod
async def update_data_ast_appr(cls, db: AsyncSession, update_data: DataAstInfoModel):
@@ -137,4 +142,4 @@ class DataAstDao:
filters = []
filters.append(DataAssetInfoAppr.flowId == flowId)
query = select(DataAssetInfoAppr).where(*filters).order_by(desc(DataAssetInfoAppr.create_time))
- return await PageUtil.paginate(db, query, 0, 0, False)
\ No newline at end of file
+ return await PageUtil.paginate(db, query, 0, 0, False)
diff --git a/vue-fastapi-backend/module_admin/service/approval_service.py b/vue-fastapi-backend/module_admin/service/approval_service.py
index afd91b8..b9729a8 100644
--- a/vue-fastapi-backend/module_admin/service/approval_service.py
+++ b/vue-fastapi-backend/module_admin/service/approval_service.py
@@ -253,6 +253,8 @@ class ApprovalService:
# logger.info(f"发现新增类型变更,准备添加数据资产,AST_NO: {appr_model.ast_no}")
main_model = DataAstInfoModel(**appr_model.model_dump(exclude_unset=True, by_alias=True))
await DataAstDao.add_dataast_data(result_db, main_model)
+ elif change_type == "delete" and appr_model.ast_no is not None:
+ await DataAstDao.delete_dataast_data_by_ast_no(result_db, appr_model.ast_no)
# logger.info(f"数据资产添加成功,AST_NO: {main_model.ast_no}")
# 更新 approStatus 状态
diff --git a/vue-fastapi-backend/module_admin/service/dataast_service.py b/vue-fastapi-backend/module_admin/service/dataast_service.py
index b0aed9d..ccb5c43 100644
--- a/vue-fastapi-backend/module_admin/service/dataast_service.py
+++ b/vue-fastapi-backend/module_admin/service/dataast_service.py
@@ -65,6 +65,28 @@ class DataAstService:
return CrudResponseModel(is_success=True, message='新增数据资产成功')
+ @classmethod
+ async def delete_dataasts_appr(cls, query_db: AsyncSession, models: DataAstApprBatchModel, username: str):
+ flowId = str(uuid.uuid4())
+ for model in models.assetItems:
+ original_onum = model.onum
+ appr_onum = str(uuid.uuid4())
+ model.onum = appr_onum
+ apprModel = DataAstApprModel(**model.model_dump(exclude_unset=True, by_alias=True))
+ apprModel.changeType = "delete"
+ apprModel.compareId = original_onum
+ apprModel.oldInstId = str(model.ast_no) if model.ast_no is not None else original_onum
+ apprModel.approStatus = "waiting"
+ apprModel.flowId = flowId
+ await DataAstDao.add_dataast_appr(query_db, apprModel)
+
+ applyModel = ApplyModel()
+ applyModel.businessType = "dataAssetMain"
+ applyModel.businessId = flowId
+ applyModel.applicant = username
+ await ApprovalService.apply_services(query_db, applyModel, 'dataAssetMain')
+ return CrudResponseModel(is_success=True, message='删除数据资产申请提交成功')
+
@classmethod
async def get_ast_main_appr_list(cls, query_db: AsyncSession, flowId: str, is_page: bool = False):
- return await DataAstDao.get_ast_main_appr_list(flowId, query_db)
\ No newline at end of file
+ return await DataAstDao.get_ast_main_appr_list(flowId, query_db)
diff --git a/vue-fastapi-backend/module_admin/service/meta_service.py b/vue-fastapi-backend/module_admin/service/meta_service.py
index d604d48..938535a 100644
--- a/vue-fastapi-backend/module_admin/service/meta_service.py
+++ b/vue-fastapi-backend/module_admin/service/meta_service.py
@@ -56,7 +56,7 @@ class MetaService:
table['hasAsset'] = '1' # 已发布
else:
hasAsset2 = await DataAssetDao.get_data_asset_appr_by_ast_no(result_db, table['extractOnum'])
- if hasAsset2:
+ if hasAsset2 and hasAsset2.approStatus == 'waiting':
table['hasAsset'] = '2' # 发布中
table['batchTabClas'] = CamelCaseUtil.transform_result(tab_list)
return meta_rel_list
diff --git a/vue-fastapi-backend/module_admin/service/metasecurity_service.py b/vue-fastapi-backend/module_admin/service/metasecurity_service.py
index a62b2a4..abc7ff9 100644
--- a/vue-fastapi-backend/module_admin/service/metasecurity_service.py
+++ b/vue-fastapi-backend/module_admin/service/metasecurity_service.py
@@ -23,6 +23,7 @@ from sqlglot.expressions import Table
from sqlglot import exp ,parse_one
from typing import Set
from sqlparse.tokens import Keyword, DML
+from urllib.parse import quote_plus
class MetaSecurityService:
"""
数据源安全管理模块服务层
@@ -379,7 +380,9 @@ class MetaSecurityService:
# 1️⃣ 去掉 jdbc 前缀
jdbc_prefixes = {
"jdbc:mysql://": len("jdbc:mysql://"),
- "jdbc:postgresql://": len("jdbc:postgresql://")
+ "jdbc:postgresql://": len("jdbc:postgresql://"),
+ "jdbc:oracle:thin:@//": len("jdbc:oracle:thin:@//"),
+ "jdbc:oracle:thin:@": len("jdbc:oracle:thin:@")
}
for prefix, length in jdbc_prefixes.items():
if address.startswith(prefix):
@@ -410,6 +413,21 @@ class MetaSecurityService:
pool_pre_ping=True,
connect_args={"timeout": 5} # ⭐ 关键
)
+ elif db_type.lower() == "oracle":
+ address = db_params["address"].lstrip("/")
+ user = quote_plus(db_params["user"])
+ password = quote_plus(db_params["password"])
+ connect_type = (db_params.get("connectType") or "").upper()
+ service_or_sid = quote_plus(db_params.get("database", ""))
+ if connect_type == "ORACLE_SID":
+ conn_str = f"oracle+oracledb://{user}:{password}@{address}/?sid={service_or_sid}"
+ else:
+ conn_str = f"oracle+oracledb://{user}:{password}@{address}/?service_name={service_or_sid}"
+ engine = create_async_engine(
+ conn_str,
+ pool_pre_ping=True,
+ connect_args={"transport_connect_timeout": 5}
+ )
else:
raise ValueError("不支持的数据库类型")
@@ -438,7 +456,8 @@ class MetaSecurityService:
try:
async with async_session() as session:
- await session.execute(text("SET statement_timeout = 30000"))
+ if (db_type or "").upper() == "POSTGRESQL":
+ await session.execute(text("SET statement_timeout = 30000"))
# ⭐ 原始数量
if sql_type == "原始结果":
count_sql = cls.build_count_sql(sql_query,db_type)
@@ -474,6 +493,7 @@ class MetaSecurityService:
if select:
select.set("order", None)
select.set("limit", None)
+ select.set("offset", None)
cleaned_sql = parsed.sql(dialect=dialect)
return f"SELECT COUNT(*) AS cnt FROM ({cleaned_sql}) t"
@@ -495,10 +515,18 @@ class MetaSecurityService:
elif db_type.lower() == "mysql":
# MySQL: 直接查询表字段(MySQL 没有 schema 的概念)
query = f"""
- SELECT COLUMN_NAME
+ SELECT COLUMN_NAME AS column_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '{table}'
"""
+ elif db_type.lower() == "oracle":
+ query = f"""
+ SELECT COLUMN_NAME AS "column_name"
+ FROM ALL_TAB_COLUMNS
+ WHERE OWNER = UPPER('{schema}')
+ AND TABLE_NAME = UPPER('{table}')
+ ORDER BY COLUMN_ID
+ """
else:
raise ValueError(f"暂不支持数据库类型: {db_type}")
diff --git a/vue-fastapi-backend/requirements.txt b/vue-fastapi-backend/requirements.txt
index 5d642c8..3d370ae 100644
--- a/vue-fastapi-backend/requirements.txt
+++ b/vue-fastapi-backend/requirements.txt
@@ -34,6 +34,7 @@ mdurl==0.1.2
minio==7.2.14
numpy==2.2.1
openpyxl==3.1.5
+oracledb==2.2.1
orjson==3.10.12
packaging==25.0
pandas==2.2.2
@@ -85,4 +86,4 @@ uvloop==0.21.0
watchfiles==1.0.3
wcwidth==0.2.13
websockets==14.1
-zope.interface==7.2
\ No newline at end of file
+zope.interface==7.2
diff --git a/vue-fastapi-frontend/src/api/dataAsset/assetDetail.js b/vue-fastapi-frontend/src/api/dataAsset/assetDetail.js
index b6a498f..e5923fc 100644
--- a/vue-fastapi-frontend/src/api/dataAsset/assetDetail.js
+++ b/vue-fastapi-frontend/src/api/dataAsset/assetDetail.js
@@ -24,6 +24,14 @@ export function batch(data) {
})
}
+export function delAstAppr(data) {
+ return request({
+ url: '/default-api/system/dataAsset/delastappr',
+ method: 'post',
+ data,
+ })
+}
+
export function deptTreeSelect() {
return request({
url: '/default-api/system/dataAsset/sources',
@@ -38,4 +46,4 @@ export function listAssetMainAppr(data) {
})
}
-
\ No newline at end of file
+
diff --git a/vue-fastapi-frontend/src/api/meta/metaInfo.js b/vue-fastapi-frontend/src/api/meta/metaInfo.js
index bcdc5e1..8b82e4d 100644
--- a/vue-fastapi-frontend/src/api/meta/metaInfo.js
+++ b/vue-fastapi-frontend/src/api/meta/metaInfo.js
@@ -1,4 +1,5 @@
import request from '@/utils/request'
+import cache from '@/plugins/cache'
// 查询参数列表
export function getDataSourceList(query) {
@@ -100,7 +101,17 @@ export function getProcData(param){
params: param
})
}
-
+export function getschemaById(id) {
+ const query = {
+ userName: cache.local.get("username"),
+ password: cache.local.get("password")
+ }
+ return request({
+ url: '/ds-api/dolphinscheduler/datasources/schemas?datasource='+id,
+ method: 'get',
+ headers: {dashUserName:query.userName,dashPassword:query.password}
+ })
+}
diff --git a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue
index 290bd18..176253f 100644
--- a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue
+++ b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue
@@ -256,7 +256,7 @@
\ No newline at end of file
+
+
+
diff --git a/vue-fastapi-frontend/src/views/meta/metatask/index.vue b/vue-fastapi-frontend/src/views/meta/metatask/index.vue
index 7d417d8..61b2f3f 100644
--- a/vue-fastapi-frontend/src/views/meta/metatask/index.vue
+++ b/vue-fastapi-frontend/src/views/meta/metatask/index.vue
@@ -500,13 +500,22 @@
-
+ >
+
+
@@ -568,6 +577,7 @@