Browse Source

数据资产发布后台

master
xueyinfei 2 days ago
parent
commit
b89073f4da
  1. 54
      vue-fastapi-backend/module_admin/controller/data_asset_controller.py
  2. 3
      vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py
  3. 16
      vue-fastapi-backend/module_admin/dao/data_asset_dao.py
  4. 149
      vue-fastapi-backend/module_admin/dao/data_ast_content_dao.py
  5. 155
      vue-fastapi-backend/module_admin/dao/dataast_dao.py
  6. 67
      vue-fastapi-backend/module_admin/entity/do/dataast_do.py
  7. 16
      vue-fastapi-backend/module_admin/entity/vo/data_asset_vo.py
  8. 69
      vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py
  9. 30
      vue-fastapi-backend/module_admin/service/approval_service.py
  10. 6
      vue-fastapi-backend/module_admin/service/data_ast_content_service.py
  11. 70
      vue-fastapi-backend/module_admin/service/dataast_service.py
  12. 31
      vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue

54
vue-fastapi-backend/module_admin/controller/data_asset_controller.py

@ -1,9 +1,13 @@
from fastapi import APIRouter, Depends, Form, Request from fastapi import APIRouter, Depends, Form, Request
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from config.get_db import get_db from config.get_db import get_db
from datetime import datetime
from module_admin.entity.vo.user_vo import CurrentUserModel
from module_admin.aspect.interface_auth import CheckUserInterfaceAuth from module_admin.aspect.interface_auth import CheckUserInterfaceAuth
from module_admin.service.login_service import LoginService from module_admin.service.login_service import LoginService
from module_admin.service.data_asset_service import DataAssetService from module_admin.service.data_asset_service import DataAssetService
from module_admin.service.dataast_service import DataAstService
from module_admin.entity.vo.dataast_vo import DataAstInfoModel, DataAstInfoPageQueryModel,DataAstApprModel,DataAstApprBatchModel
from module_admin.entity.vo.data_asset_vo import DataAssetBatchModel, DataAssetPageQueryModel, DataAssetResultModel, DataAssetSearchModel from module_admin.entity.vo.data_asset_vo import DataAssetBatchModel, DataAssetPageQueryModel, DataAssetResultModel, DataAssetSearchModel
from utils.log_util import logger from utils.log_util import logger
from utils.page_util import PageResponseModel from utils.page_util import PageResponseModel
@ -145,3 +149,53 @@ async def export_data_assets(
logger.info('导出成功') logger.info('导出成功')
return ResponseUtil.streaming(data=bytes2file_response(excel_data)) return ResponseUtil.streaming(data=bytes2file_response(excel_data))
# ----------------------------------------------------------------元数据发布相关接口----------------------------------------------------------------------------------------------------
# @dataAssetController.post('/addastappr')
# @Log(title='数据资产新增申请', business_type=BusinessType.INSERT)
# async def add_dataast_appr(
# request: Request,
# add_dataast: DataAstApprModel,
# query_db: AsyncSession = Depends(get_db),
# current_user: CurrentUserModel = Depends(LoginService.get_current_user),
# ):
# add_dataast.create_by = current_user.user.user_name
# add_dataast.create_time = datetime.now()
# add_dataast.upd_prsn = current_user.user.user_name
# add_dataast.upd_time = datetime.now()
# add_dataast_result = await DataAstService.add_dataast_appr(query_db, add_dataast)
# logger.info(add_dataast_result.message)
# return ResponseUtil.success(msg=add_dataast_result.message)
@dataAssetController.post('/addastappr')
@Log(title='数据资产新增申请', business_type=BusinessType.INSERT)
async def add_dataast_appr(
request: Request,
add_dataasts: DataAstApprBatchModel, # 修改为列表
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
for add_dataast in add_dataasts.assetItems:
add_dataast.create_by = current_user.user.user_name
add_dataast.create_time = datetime.now()
add_dataast.upd_prsn = current_user.user.user_name
add_dataast.upd_time = datetime.now()
add_dataast_result = await DataAstService.add_dataasts_appr(query_db, add_dataasts,current_user.user.user_name)
logger.info(add_dataast_result.message)
return ResponseUtil.success(msg=add_dataast_result.message)
@dataAssetController.get('/listastappr', response_model=PageResponseModel
)
async def get_ast_main_appr_list(
request: Request,
main_page_query: DataAstApprModel= Depends(DataAstApprModel),
query_db: AsyncSession = Depends(get_db),
):
main_page_query_result = await DataAstService.get_ast_main_appr_list(query_db, main_page_query, is_page=True)
logger.info('获取数据标准列表成功')
return ResponseUtil.success(data=main_page_query_result)

3
vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py

@ -199,7 +199,8 @@ async def removerel_data_ast_catalog(
current_user: CurrentUserModel = Depends(LoginService.get_current_user), current_user: CurrentUserModel = Depends(LoginService.get_current_user),
): ):
# 调用服务层方法 # 调用服务层方法
removerel_result = await DataCatalogService.removerel_data_ast_catalog_services(query_db, removerel_catalog) user_name = current_user.user.user_name
removerel_result = await DataCatalogService.removerel_data_ast_catalog_services(query_db, removerel_catalog,user_name)
logger.info(removerel_result.message) logger.info(removerel_result.message)
# 返回标准化响应 # 返回标准化响应

16
vue-fastapi-backend/module_admin/dao/data_asset_dao.py

@ -1,6 +1,7 @@
from sqlalchemy import select, update, delete, insert from sqlalchemy import select, update, delete, insert
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.data_ast_content_do import DataAssetInfo from module_admin.entity.do.data_ast_content_do import DataAssetInfo
from module_admin.entity.do.dataast_do import DataAssetInfoAppr
from module_admin.entity.vo.data_asset_vo import DataAssetItemModel, DataAssetPageQueryModel from module_admin.entity.vo.data_asset_vo import DataAssetItemModel, DataAssetPageQueryModel
from utils.page_util import PageUtil from utils.page_util import PageUtil
from typing import List, Dict, Any from typing import List, Dict, Any
@ -82,6 +83,8 @@ class DataAssetDao:
) )
return result.rowcount return result.rowcount
@classmethod @classmethod
async def delete_data_asset(cls, db: AsyncSession, ast_no: str): async def delete_data_asset(cls, db: AsyncSession, ast_no: str):
""" """
@ -91,11 +94,24 @@ class DataAssetDao:
:param ast_no: 资产编号 :param ast_no: 资产编号
:return: 删除结果 :return: 删除结果
""" """
# 更新t_data_ast_info_appr表中对应记录的状态为0(无效)
await db.execute(
update(DataAssetInfoAppr)
.where(DataAssetInfoAppr.ast_no == ast_no)
.values(data_ast_stat='0')
)
# 删除t_data_ast_info表中的记录
result = await db.execute( result = await db.execute(
delete(DataAssetInfo) delete(DataAssetInfo)
.where(DataAssetInfo.ast_no == ast_no) .where(DataAssetInfo.ast_no == ast_no)
) )
# 提交事务
await db.commit()
return result.rowcount return result.rowcount
@classmethod @classmethod
async def get_data_asset_sources(cls, db: AsyncSession): async def get_data_asset_sources(cls, db: AsyncSession):
""" """

149
vue-fastapi-backend/module_admin/dao/data_ast_content_dao.py

@ -61,91 +61,6 @@ class DataCatalogDAO:
# @classmethod
# async def get_catalog_list(cls, db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, is_page: bool = False):
# """
# 根据查询参数获取数据资产目录列表
# :param db: 异步会话对象
# :param query_object: 分页查询参数对象
# :param is_page: 是否分页
# :return: 数据资产目录分页列表
# """
# 创建别名对象
# t1 = aliased(DataAstContentRela, name='t1')
# t2 = aliased(DataAstInfo, name='t2')
# t3 = aliased(DataAstBookmarkRela, name='t3')
# # 修改子查询部分
# subquery_t1 = (
# select(DataAstContentRela)
# .where(DataAstContentRela.upd_prsn == query_object.upd_prsn, DataAstContentRela.content_onum == '2' and DataAstContentRela.rela_status == '1')
# .union_all(
# select(DataAstContentRela)
# .where(DataAstContentRela.content_onum != '2' and DataAstContentRela.rela_status == '1')
# )
# ).alias('subquery_t1') # 为子查询分配唯一别名
# query = (
# select(
# DataAstContent.content_onum,
# DataAstContent.content_name,
# DataAstContent.content_stat,
# DataAstContent.content_intr,
# DataAstContent.content_pic,
# DataAstContent.supr_content_onum,
# DataAstContent.leaf_node_flag,
# DataAstContent.upd_prsn,
# DataAstContent.upd_time,
# subquery_t1.c.rela_onum, # 明确指定子查询的字段
# subquery_t1.c.ast_onum,
# subquery_t1.c.rela_type,
# subquery_t1.c.rela_eff_begn_date,
# subquery_t1.c.rela_eff_end_date,
# subquery_t1.c.upd_prsn,
# t2.data_ast_no,
# t2.data_ast_eng_name,
# t2.data_ast_cn_name,
# t2.data_ast_type,
# t2.data_ast_stat,
# t2.data_ast_desc,
# t2.data_ast_clas,
# t2.data_ast_cont,
# t2.data_ast_faq,
# t2.data_ast_estb_time,
# t2.data_ast_upd_time,
# t2.data_ast_src,
# t2.ast_no,
# t3.bookmark_orde,
# case(
# (t3.rela_onum.isnot(None), 1),
# else_=0
# ).label('bookmark_flag')
# )
# .distinct()
# .select_from(DataAstContent)
# .outerjoin(subquery_t1, DataAstContent.content_onum == subquery_t1.c.content_onum) # 明确使用子查询别名
# .outerjoin(t2, subquery_t1.c.ast_onum == t2.ast_no)
# .outerjoin(t3, and_(
# subquery_t1.c.ast_onum == t3.data_ast_no,
# t3.user_id == user_id
# ))
# .where(DataAstContent.content_stat == 1)
# .order_by(DataAstContent.content_onum)
# )
# # 使用分页工具进行查询
# data_ast_list = await PageUtil.paginate(
# db,
# query,
# page_num=query_object.page_num,
# page_size=query_object.page_size,
# is_page=is_page
# )
# return data_ast_list
@classmethod @classmethod
async def get_catalog_list(cls, db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, user_name: str, is_page: bool = False): async def get_catalog_list(cls, db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, user_name: str, is_page: bool = False):
@ -530,25 +445,53 @@ class DataCatalogDAO:
await cls.update_leaf_node_flag(db) await cls.update_leaf_node_flag(db)
@classmethod @classmethod
async def removerel_data_ast_catalog_dao(cls, db: AsyncSession, removerel_catalog_data: dict): async def removerel_data_ast_catalog_dao(cls, db: AsyncSession, removerel_catalog_data: dict):
""" """
编辑资产关系数据库操作 编辑资产关系数据库操作
当删除目录下某个子资产时要更新该用户收藏的其他资产关系
:param db: orm对象 :param db: orm对象
:param catalog: 需要更新的目录字典 :param catalog: 需要更新的目录字典
:return: :return: 更新的记录数量
""" """
logger.info(f"开始处理资产关系更新,参数: {removerel_catalog_data}")
try:
# 1. 查询满足条件的所有 rela_onum
logger.debug("开始查询相关资产关系记录...")
query = select(DataAstContentRela.rela_onum).where(
DataAstContentRela.ast_onum == removerel_catalog_data['ast_onum'],
DataAstContentRela.upd_prsn == removerel_catalog_data['upd_prsn']
)
# 执行异步查询
result = await db.execute(query)
rela_onum_list = [row[0] for row in result.fetchall()]
logger.info(f"查询完成,找到 {len(rela_onum_list)} 条相关记录")
# 2. 根据 rela_onum 列表更新状态
if rela_onum_list:
logger.debug(f"开始更新 {len(rela_onum_list)} 条记录的状态...")
stmt = ( stmt = (
update(DataAstContentRela) update(DataAstContentRela)
.where(DataAstContentRela.rela_onum == removerel_catalog_data['rela_onum'] , DataAstContentRela.content_onum == removerel_catalog_data['content_onum']) .where(DataAstContentRela.rela_onum.in_(rela_onum_list))
.values( .values(rela_status=removerel_catalog_data['rela_status'])
rela_status=removerel_catalog_data['rela_status'] )
) )
await db.execute(stmt) await db.execute(stmt)
await cls.update_leaf_node_flag(db) await cls.update_leaf_node_flag(db)
await db.commit() # 提交事务
logger.info(f"成功更新 {len(rela_onum_list)} 条记录的状态为: {removerel_catalog_data['rela_status']}")
return len(rela_onum_list)
else:
logger.info("没有找到符合条件的记录,无需更新")
return 0
except Exception as e:
logger.error(f"处理资产关系更新时发生错误: {str(e)}", exc_info=True)
await db.rollback() # 回滚事务
raise # 重新抛出异常,由上层处理
@classmethod @classmethod
@ -705,20 +648,15 @@ class DataCatalogDAO:
@classmethod @classmethod
async def delete_ast_book_mark_rela_by_content_onum(cls, db: AsyncSession, content_onum: int, user_id: int): async def delete_ast_book_mark_rela_by_content_onum(cls, db: AsyncSession, content_onum: int, user_id: int):
""" """
根据目录ID和用户ID删除收藏关系 根据目录ID和用户ID删除收藏关系修正CTE语法
:param db: orm对象
:param content_onum: 目录ID
:param user_id: 用户ID
:return:
""" """
# 创建别名对象 # 创建别名对象
t1 = aliased(DataAstContentRela, name='t1') t1 = aliased(DataAstContentRela, name='t1')
t2 = aliased(DataAssetInfo, name='t2') t2 = aliased(DataAssetInfo, name='t2')
t3 = aliased(DataAstBookmarkRela, name='t3') t3 = aliased(DataAstBookmarkRela, name='t3')
# 使用子查询替代CTE
cte = ( subquery = (
select(t3.rela_onum) select(t3.rela_onum)
.select_from(DataAstContent) .select_from(DataAstContent)
.outerjoin(t1, DataAstContent.content_onum == t1.content_onum) .outerjoin(t1, DataAstContent.content_onum == t1.content_onum)
@ -728,17 +666,22 @@ class DataCatalogDAO:
t3.user_id == user_id t3.user_id == user_id
)) ))
.where(DataAstContent.content_onum == content_onum) .where(DataAstContent.content_onum == content_onum)
).cte('cte') .subquery()
)
# 直接使用子查询构造DELETE语句
stmt = ( stmt = (
delete(DataAstBookmarkRela) delete(DataAstBookmarkRela)
.where(DataAstBookmarkRela.rela_onum.in_(select(cte.c.rela_onum))) .where(
DataAstBookmarkRela.rela_onum.in_(
select(subquery.c.rela_onum)
)
)
) )
await db.execute(stmt) await db.execute(stmt)
await db.commit() await db.commit()
logger.info(" 删除收藏关系,操作成功") logger.info("删除收藏关系,操作成功")
@classmethod @classmethod

155
vue-fastapi-backend/module_admin/dao/dataast_dao.py

@ -0,0 +1,155 @@
from sqlalchemy import delete, select, update, desc,or_,not_,insert,and_,func
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.dataast_do import DataAssetInfoAppr
from module_admin.entity.do.data_ast_content_do import DataAssetInfo
from module_admin.entity.vo.dataast_vo import DataAstApprModel,DataAstInfoModel
from utils.page_util import PageUtil
from sqlalchemy.orm import aliased
from datetime import datetime
class DataAstDao:
@classmethod
async def get_dataast_appr_list(cls, flowId:str,db: AsyncSession):
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)
@classmethod
async def get_dataast_appr_list_Flow(cls, flowId:str,db: AsyncSession):
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)
@classmethod
async def add_dataast_appr(cls, db: AsyncSession, model: DataAstApprModel):
# 从model中获取ast_no
ast_no = model.ast_no
# 查询当前ast_no对应的最大版本号
from sqlalchemy import select, func
query = select(func.max(DataAssetInfoAppr.version_no)).where(
DataAssetInfoAppr.ast_no == ast_no
)
result = await db.execute(query)
max_version = result.scalar_one_or_none()
# 计算新的版本号
new_version = '1' if max_version is None else str(int(max_version) + 1)
# 创建对象时设置版本号
data = model.model_dump()
data['version_no'] = new_version
col = DataAssetInfoAppr(**data)
db.add(col)
await db.flush()
return col
@classmethod
async def add_dataast_data(cls, db: AsyncSession, model: DataAstInfoModel):
# 子查询:获取每个 ast_no 对应的最新已成功审批版本
subquery = (
select(
DataAssetInfoAppr.ast_no,
func.max(DataAssetInfoAppr.version_no).label("max_version")
)
.filter(
DataAssetInfoAppr.approStatus == "succeed"
)
.group_by(DataAssetInfoAppr.ast_no)
.subquery()
)
# 主查询:筛选符合条件的记录并映射到目标模型
query = (
select(DataAssetInfoAppr)
.join(
subquery,
and_(
DataAssetInfoAppr.ast_no == subquery.c.ast_no,
DataAssetInfoAppr.version_no == subquery.c.max_version
)
)
.filter(
DataAssetInfoAppr.data_ast_stat == "1",
DataAssetInfoAppr.changeType == "add",
DataAssetInfoAppr.approStatus == "succeed"
)
)
# 执行查询获取符合条件的记录
approved_records = await db.scalars(query)
# 收集需要处理的记录数据
records_to_upsert = []
for record in approved_records:
# 从源记录中提取需要的字段
asset_data = {
"data_ast_eng_name": record.data_ast_eng_name,
"data_ast_cn_name": record.data_ast_cn_name,
"data_ast_type": record.data_ast_type,
"data_ast_stat": record.data_ast_stat,
"data_ast_desc": record.data_ast_desc,
"data_ast_screen": record.data_ast_screen,
"data_ast_scren_clas": record.data_ast_scren_clas,
"data_ast_cont": record.data_ast_cont,
"data_ast_faq": record.data_ast_faq,
"data_ast_estb_time": record.data_ast_estb_time,
"data_ast_upd_time": datetime.now(), # 使用当前时间
"data_ast_src": record.data_ast_src,
"ast_no": record.ast_no,
"data_ast_clas": record.data_ast_clas
}
records_to_upsert.append(asset_data)
# 使用 bulk_insert_mappings 执行批量插入/更新
if records_to_upsert:
from sqlalchemy.dialects.mysql import insert
insert_stmt = insert(DataAssetInfo).values(records_to_upsert)
# 定义 ON DUPLICATE KEY UPDATE 子句
update_dict = {
c.name: insert_stmt.inserted[c.name]
for c in DataAssetInfo.__table__.columns
if c.name != 'data_ast_no' and c.name != 'ast_no' # 排除主键和业务主键
}
# 手动设置 upd_time 为当前时间
update_dict['data_ast_upd_time'] = datetime.now()
upsert_stmt = insert_stmt.on_duplicate_key_update(update_dict)
# 执行插入/更新语句
await db.execute(upsert_stmt)
# 提交会话使更改生效
await db.commit()
return "元数据成功发布到数据资产!"
@classmethod
async def update_data_ast_appr(cls, db: AsyncSession, update_data: DataAstInfoModel):
await db.execute(update(DataAssetInfoAppr), [update_data])
await db.flush()
@classmethod
async def get_ast_main_appr_list(cls, flowId:str,db: AsyncSession):
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)

67
vue-fastapi-backend/module_admin/entity/do/dataast_do.py

@ -0,0 +1,67 @@
from sqlalchemy import Column, String, Integer, Text, DateTime
from sqlalchemy.sql import func
from config.database import Base
class DataAssetInfoAppr(Base):
__tablename__ = 't_data_ast_info_appr'
onum = Column(String(255), primary_key=True, comment='数据资产序号')
data_ast_eng_name = Column(String(255), nullable=True, comment='数据资产英文名称')
data_ast_cn_name = Column(String(255), nullable=True, comment='数据资产中文名称')
data_ast_type = Column(String(50), nullable=True, comment='数据资产类型')
data_ast_stat = Column(String(50), nullable=True, comment='数据资产状态(1:有效 0:无效)')
data_ast_desc = Column(Text, nullable=True, comment='数据资产描述/说明')
data_ast_screen = Column(String(255), nullable=True, comment='资产应用场景')
data_ast_scren_clas = Column(String(255), nullable=True, comment='应用场景分类')
data_ast_cont = Column(Text, nullable=True, comment='数据资产内容')
data_ast_faq = Column(Text, nullable=True, comment='数据资产常见问题')
data_ast_estb_time = Column(DateTime, nullable=True, server_default=func.now(), comment='数据资产建立时间')
data_ast_upd_time = Column(DateTime, nullable=True, server_default=func.now(), onupdate=func.now(), comment='数据资产更新时间')
data_ast_src = Column(String(255), nullable=True, comment='数据资产来源')
ast_no = Column(Integer, nullable=True, comment='数据资产编号')
data_ast_clas = Column(String(255), nullable=True, comment='数据资产标签')
version_no = Column(String(50), nullable=True, comment='版本号')
changeType = Column(String(10), default=None, comment='变更类型')
flowId = Column(String(50), default=None, comment='审批Id')
oldInstId = Column(String(50), default=None, comment='原始正式id')
compareId = Column(String(50), default=None, comment='原始数据id(用于对比差异)')
approStatus = Column(String(10), default=None, comment='审批状态(waiting,申请中,pending审核中,succeed,rejected已审核,canceled已取消)')
create_by = Column(String(255), nullable=True, comment='创建人')
create_time = Column(DateTime, nullable=True, server_default=func.now(), comment='创建时间')
upd_prsn = Column(String(255), nullable=True, comment='更新人')
upd_time = Column(DateTime, nullable=True, server_default=func.now(), onupdate=func.now(), comment='更新时间')
# class MetadataSuppInfo(Base):
# __tablename__ = 't_metadata_supp_info'
# onum = Column(String(36), primary_key=True, comment='唯一编号')
# crrct_ver_num = Column(String(50), comment='补录版本号')
# ssys_cd = Column(String(50), comment='系统代码')
# mdl_name = Column(String(50), comment='模型名称')
# tab_eng_name = Column(String(250), comment='表英文名称')
# tab_crrct_name = Column(String(250), comment='表补录名称')
# tab_desc = Column(String(500), comment='表描述')
# pic = Column(String(64), comment='表图片')
# gov_flag = Column(String(1), comment='治理标志(0否 1是)')
# rec_stat = Column(String(1), comment='记录状态(0有效 1无效)')
# tab_clas = Column(Text, comment='表分类')
# rec_subm_prsn = Column(String(255), comment='记录提交人')
# upd_time = Column(DateTime, default=func.now(), onupdate=func.now(), comment='更新时间')
# class MetadataExtractInfo(Base):
# __tablename__ = 't_metadata_extract_info'
# onum = Column(Integer, primary_key=True, comment='唯一编号')
# extract_ver_num = Column(String(50), comment='采集版本号')
# ver_desc = Column(String(250), comment='版本描述')
# ssys_cd = Column(String(50), comment='系统代码')
# data_whs_name = Column(String(50), comment='数据仓库名称')
# mdl_name = Column(String(50), comment='模式名称')
# tab_no = Column(Integer, comment='表编号')
# tab_type = Column(String(50), comment='表类型')
# tab_eng_name = Column(String(250), comment='表英文名称')
# tab_cn_name = Column(String(250), comment='表中文名称')
# tab_rec_num = Column(Integer, comment='记录数')
# upd_time = Column(DateTime, default=func.now(), onupdate=func.now(), comment='更新时间')

16
vue-fastapi-backend/module_admin/entity/vo/data_asset_vo.py

@ -19,11 +19,19 @@ class DataAssetItemModel(BaseModel):
data_ast_type: str = Field(default=None, alias="dataAstType", description='数据资产类型(表/报表/数据应用)(必填)') data_ast_type: str = Field(default=None, alias="dataAstType", description='数据资产类型(表/报表/数据应用)(必填)')
data_ast_stat: str = Field(default=None, alias="dataAstStat", description='数据资产状态(有效/废弃)(必填)') data_ast_stat: str = Field(default=None, alias="dataAstStat", description='数据资产状态(有效/废弃)(必填)')
data_ast_desc: str = Field(default=None, alias="dataAstDesc", description='数据资产描述') data_ast_desc: str = Field(default=None, alias="dataAstDesc", description='数据资产描述')
data_ast_screen: str = Field(default=None, alias="dataAstScreen", description='资产应用场景(API/智能问答等)')
data_ast_scren_clas: str = Field(default=None, alias="dataAstScrenClas", description='应用场景分类') data_ast_screen: Optional[str] = Field(default=None, alias="dataAstScreen", description='资产应用场景(API/智能问答等)')
data_ast_scren_clas: Optional[str] = Field(default=None, alias="dataAstScrenClas", description='应用场景分类')
data_ast_clas: str = Field(default=None, alias="dataAstClas", description='数据资产标签') data_ast_clas: str = Field(default=None, alias="dataAstClas", description='数据资产标签')
data_ast_cont: str = Field(default=None, alias="dataAstCont", description='数据资产内容') data_ast_cont: Optional[str] = Field(default=None, alias="dataAstCont", description='数据资产内容')
data_ast_faq: str = Field(default=None, alias="dataAstFaq", description='数据资产常见问题') data_ast_faq: Optional[str] = Field(default=None, alias="dataAstFaq", description='数据资产常见问题')
# data_ast_screen: str = Field(default=None, alias="dataAstScreen", description='资产应用场景(API/智能问答等)')
# data_ast_scren_clas: str = Field(default=None, alias="dataAstScrenClas", description='应用场景分类')
# data_ast_clas: str = Field(default=None, alias="dataAstClas", description='数据资产标签')
# data_ast_cont: str = Field(default=None, alias="dataAstCont", description='数据资产内容')
# data_ast_faq: str = Field(default=None, alias="dataAstFaq", description='数据资产常见问题')
data_ast_src: str = Field(default=None, alias="dataAstSrc", description='数据资产来源(必填)') data_ast_src: str = Field(default=None, alias="dataAstSrc", description='数据资产来源(必填)')
version_no: str = Field(default="1", alias="versionNo", description='版本号(默认最新)') version_no: str = Field(default="1", alias="versionNo", description='版本号(默认最新)')
ctrl_flag: str = Field(default=None, alias="ctrlFlag", description='操作类型 1:插入 2:删除 3:更新') ctrl_flag: str = Field(default=None, alias="ctrlFlag", description='操作类型 1:插入 2:删除 3:更新')

69
vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py

@ -0,0 +1,69 @@
from pydantic import BaseModel
from typing import Optional,List
from datetime import datetime
from pydantic.alias_generators import to_camel
from module_admin.annotation.pydantic_annotation import as_query
from pydantic import ConfigDict, Field
class DataAstInfoModel(BaseModel):
"""
数据资产信息模型 (对应 t_data_ast_info_appr )
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
class DataAstInfoModel(BaseModel):
"""
数据资产信息模型 (对应 t_data_ast_info_appr )
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
onum: Optional[str] = Field(default=None, description='序号', alias='onum')
data_ast_eng_name: Optional[str] = Field(default=None, description='数据资产英文名称', alias='dataAstEngName')
data_ast_cn_name: Optional[str] = Field(default=None, description='数据资产中文名称', alias='dataAstCnName')
data_ast_type: Optional[str] = Field(default=None, description='数据资产类型', alias='dataAstType')
data_ast_stat: Optional[str] = Field(default=None, description='数据资产状态', alias='dataAstStat')
data_ast_desc: Optional[str] = Field(default=None, description='数据资产描述/说明', alias='dataAstDesc')
data_ast_screen: Optional[str] = Field(default=None, description='资产应用场景', alias='dataAstScreen')
data_ast_scren_clas: Optional[str] = Field(default=None, description='应用场景分类', alias='dataAstScrenClas')
data_ast_cont: Optional[str] = Field(default=None, description='数据资产内容', alias='dataAstCont')
data_ast_faq: Optional[str] = Field(default=None, description='数据资产常见问题', alias='dataAstFaq')
data_ast_estb_time: Optional[datetime] = Field(default=None, description='数据资产建立时间', alias='dataAstEstbTime')
data_ast_upd_time: Optional[datetime] = Field(default=None, description='数据资产更新时间', alias='dataAstUpdTime')
data_ast_src: Optional[str] = Field(default=None, description='数据资产来源', alias='dataAstSrc')
ast_no: Optional[int] = Field(default=None, description='数据资产编号', alias='astNo')
data_ast_clas: Optional[str] = Field(default=None, description='数据资产标签', alias='dataAstClas')
version_no: Optional[str] = Field(default=None, description='版本号', alias='versionNo')
create_by: Optional[str] = Field(default=None, description='创建人', alias='createBy')
create_time: Optional[datetime] = Field(default=None, description='创建时间', alias='createTime')
upd_prsn: Optional[str] = Field(default=None, description='更新者', alias='updPrsn')
upd_time: Optional[datetime] = Field(default=None, description='更新时间', alias='updTime')
@as_query
class DataAstInfoPageQueryModel(DataAstInfoModel):
"""
数据资产分页查询模型
"""
page_num: int = Field(default=1, description='当前页码')
page_size: int = Field(default=10, description='每页记录数')
class DataAstApprModel(DataAstInfoModel):
"""
数据资产审批申请模型
"""
changeType: Optional[str] = Field(default=None, description='变更类型')
flowId: Optional[str] = Field(default=None, description='审批Id')
oldInstId: Optional[str] = Field(default=None, description='原始正式id')
compareId: Optional[str] = Field(default=None, description='原始数据id(用于对比差异)')
approStatus: Optional[str] = Field(default=None, description='审批状态(waiting,申请中,pending审核中,succeed,rejected已审核,canceled已取消)')
class DataAstApprBatchModel(BaseModel):
"""
数据资产审批申请批量提交模型
"""
assetItems: List[DataAstApprModel]

30
vue-fastapi-backend/module_admin/service/approval_service.py

@ -14,9 +14,12 @@ from module_admin.dao.approval_dao import ApprovalDao
from module_admin.dao.user_dao import UserDao from module_admin.dao.user_dao import UserDao
from module_admin.dao.meta_dao import MetaDao from module_admin.dao.meta_dao import MetaDao
from module_admin.dao.datastd_dao import DataStdDao from module_admin.dao.datastd_dao import DataStdDao
from module_admin.dao.dataast_dao import DataAstDao
from module_admin.entity.vo.dataast_vo import DataAstApprModel,DataAstInfoModel
from module_admin.entity.vo.datastd_vo import DataStdCodeModel,DataStdDictModel,DataStdMainModel,DataStdMainApprModel,DataStdDictApprModel,DataStdDictModel,DataStdCodeApprModel from module_admin.entity.vo.datastd_vo import DataStdCodeModel,DataStdDictModel,DataStdMainModel,DataStdMainApprModel,DataStdDictApprModel,DataStdDictModel,DataStdCodeApprModel
class ApprovalService: class ApprovalService:
""" """
智能问答服务层 智能问答服务层
@ -100,6 +103,9 @@ class ApprovalService:
# 标准代码审批 # 标准代码审批
elif flow_approval.businessType == 'dataStdCode': elif flow_approval.businessType == 'dataStdCode':
await cls.syncStdCodeInfo(result_db, flow_approval.businessId, edit.status) await cls.syncStdCodeInfo(result_db, flow_approval.businessId, edit.status)
# 数据资产审批
elif flow_approval.businessType == 'dataAssetMain':
await cls.syncDataAstInfo(result_db, flow_approval.businessId, edit.status)
await ApprovalDao.edit_flow_approval(result_db, edit.model_dump(exclude_unset=True)) await ApprovalDao.edit_flow_approval(result_db, edit.model_dump(exclude_unset=True))
await result_db.commit() await result_db.commit()
return CrudResponseModel(is_success=True, message='操作成功') return CrudResponseModel(is_success=True, message='操作成功')
@ -229,6 +235,30 @@ class ApprovalService:
await DataStdDao.update_std_code_appr(result_db, main_appro_model.model_dump(exclude_unset=True)) await DataStdDao.update_std_code_appr(result_db, main_appro_model.model_dump(exclude_unset=True))
return CrudResponseModel(is_success=True, message='操作成功') return CrudResponseModel(is_success=True, message='操作成功')
@classmethod
async def syncDataAstInfo(cls, result_db: AsyncSession, suppId: str, operateType: str):
apprList = await DataAstDao.get_dataast_appr_list_Flow(suppId, result_db)
for appr in apprList:
# 将 SQLAlchemy 模型实例转换为 Pydantic 模型实例
appr_model = DataAstApprModel.model_validate(appr)
change_type = appr_model.changeType
if operateType =='succeed':
if change_type == "add":
# 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)
# logger.info(f"数据资产添加成功,AST_NO: {main_model.ast_no}")
# 更新 approStatus 状态
appr_model.approStatus = operateType
main_appro_model = DataStdCodeApprModel(**appr_model.model_dump(exclude_unset=True, by_alias=True))
await DataAstDao.update_data_ast_appr(result_db, main_appro_model.model_dump(exclude_unset=True))
return CrudResponseModel(is_success=True, message='操作成功')
@classmethod @classmethod

6
vue-fastapi-backend/module_admin/service/data_ast_content_service.py

@ -31,7 +31,7 @@ class DataCatalogService:
:return: 数据目录列表信息对象 :return: 数据目录列表信息对象
""" """
catalog_list_result = await DataCatalogDAO.get_catalog_list(query_db, query_object, user_id, user_name, is_page) catalog_list_result = await DataCatalogDAO.get_catalog_list(query_db, query_object, user_id, user_name, is_page)
print('获取数据清单内容111:',catalog_list_result)
# 按contentOnum分组 # 按contentOnum分组
grouped = defaultdict(list) grouped = defaultdict(list)
for item in catalog_list_result.rows: for item in catalog_list_result.rows:
@ -342,7 +342,7 @@ class DataCatalogService:
@classmethod @classmethod
async def removerel_data_ast_catalog_services(cls, query_db: AsyncSession, request: DataCatalogChild): async def removerel_data_ast_catalog_services(cls, query_db: AsyncSession, request: DataCatalogChild,user_name:str):
""" """
移除数据资产目录service 移除数据资产目录service
@ -355,7 +355,7 @@ class DataCatalogService:
'rela_type': request.rela_type, 'rela_type': request.rela_type,
'rela_eff_begn_date': request.rela_eff_begn_date, 'rela_eff_begn_date': request.rela_eff_begn_date,
'rela_eff_end_date': request.rela_eff_end_date, 'rela_eff_end_date': request.rela_eff_end_date,
'upd_prsn': request.upd_prsn, 'upd_prsn': user_name,
'rela_status': request.rela_status 'rela_status': request.rela_status
} }

70
vue-fastapi-backend/module_admin/service/dataast_service.py

@ -0,0 +1,70 @@
from fastapi import Request
from sqlalchemy.ext.asyncio import AsyncSession
from exceptions.exception import ServiceException
from module_admin.dao.dataast_dao import DataAstDao
from module_admin.entity.vo.dataast_vo import DataAstApprModel,DataAstInfoModel,DataAstApprBatchModel
from utils.common_util import CamelCaseUtil
import uuid
from module_admin.entity.vo.approval_vo import ApplyModel
from module_admin.service.approval_service import ApprovalService
from module_admin.entity.vo.common_vo import CrudResponseModel
class DataAstService:
"""
数据源标准服务层
"""
@classmethod
async def get_dataast_appr_list(cls, query_db: AsyncSession, query_object: DataAstApprModel, is_page: bool = False):
return await DataAstDao.get_dataast_appr_list(query_object.flowId, query_db)
# @classmethod
# async def add_dataasts_appr(cls, query_db: AsyncSession, model: DataAstInfoModel):
# # if not await cls.check_dict_unique_services(query_db, model):
# # raise ServiceException(message=f"数据资产编号 {model.ast_no} 已存在")
# model.onum=str(uuid.uuid4())
# model.data_ast_stat="1"
# apprModel = DataAstApprModel(**model.model_dump(exclude_unset=True, by_alias=True))
# apprModel.changeType="add"
# apprModel.compareId=model.onum
# apprModel.oldInstId=model.onum
# apprModel.approStatus="waiting"
# apprModel.flowId=str(uuid.uuid4())
# await DataAstDao.add_dataast_appr(query_db, apprModel)
# applyModel = ApplyModel()
# applyModel.businessType = "dataAssetMain"
# applyModel.businessId = apprModel.flowId
# applyModel.applicant = apprModel.create_by
# await ApprovalService.apply_services(query_db, applyModel, 'dataAssetMain')
# return CrudResponseModel(is_success=True, message='新增数据资产成功')
@classmethod
async def add_dataasts_appr(cls, query_db: AsyncSession, models: DataAstApprBatchModel,username: str):
# if not await cls.check_dict_unique_services(query_db, model):
# raise ServiceException(message=f"数据资产编号 {model.ast_no} 已存在")
flowId = str(uuid.uuid4()) #流程编号
for model in models.assetItems:
model.onum=str(uuid.uuid4())
model.data_ast_stat="1"
apprModel = DataAstApprModel(**model.model_dump(exclude_unset=True, by_alias=True))
apprModel.changeType="add"
apprModel.compareId=model.onum
apprModel.oldInstId=model.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, query_object: DataAstInfoModel, is_page: bool = False):
return await DataAstDao.get_ast_main_appr_list(query_object.flowId, query_db)

31
vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue

@ -115,6 +115,17 @@
<el-dialog title="编辑资产" v-model="open" width="600px" append-to-body> <el-dialog title="编辑资产" v-model="open" width="600px" append-to-body>
<el-form :model="form" :rules="rules" ref="assetRef" label-width="120px"> <el-form :model="form" :rules="rules" ref="assetRef" label-width="120px">
<el-form-item label="资产编号" prop="astNo"> <el-form-item label="资产编号" prop="astNo">
<el-input v-model="form.astNo" placeholder="请输入" :disabled="true" />
</el-form-item>
<el-form-item label="表英文名称" prop="dataAstEngName">
<el-input v-model="form.dataAstEngName" placeholder="请输入" :disabled="true" />
</el-form-item>
<el-form-item label="表中文名称" prop="dataAstCnName">
<el-input v-model="form.dataAstCnName" placeholder="请输入" :disabled="true" />
</el-form-item>
<el-form-item label="表类型" prop="dataAstType">
<el-select v-model="form.dataAstType" placeholder="请选择" clearable style="width: 100%" :disabled="true">
<!-- <el-form-item label="资产编号" prop="astNo">
<el-input v-model="form.astNo" placeholder="请输入" /> <el-input v-model="form.astNo" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="资产英文名称" prop="dataAstEngName"> <el-form-item label="资产英文名称" prop="dataAstEngName">
@ -124,17 +135,17 @@
<el-input v-model="form.dataAstCnName" placeholder="请输入" /> <el-input v-model="form.dataAstCnName" placeholder="请输入" />
</el-form-item> </el-form-item>
<el-form-item label="资产类型" prop="dataAstType"> <el-form-item label="资产类型" prop="dataAstType">
<el-select v-model="form.dataAstType" placeholder="请选择" clearable style="width: 100%"> <el-select v-model="form.dataAstType" placeholder="请选择" clearable style="width: 100%"> -->
<el-option label="表" value="表" /> <el-option label="表" value="表" />
<el-option label="报表" value="报表" /> <el-option label="报表" value="报表" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="资产状态" prop="dataAstStat"> <!-- <el-form-item label="资产状态" prop="dataAstStat">
<el-select v-model="form.dataAstStat" placeholder="请选择" clearable style="width: 100%"> <el-select v-model="form.dataAstStat" placeholder="请选择" clearable style="width: 100%">
<el-option label="有效" value="1" /> <el-option label="有效" value="1" />
<el-option label="作废" value="0" /> <el-option label="作废" value="0" />
</el-select> </el-select>
</el-form-item> </el-form-item> -->
<el-form-item label="资产应用场景" prop="dataAstScreen"> <el-form-item label="资产应用场景" prop="dataAstScreen">
<el-select v-model="form.dataAstScreen" placeholder="请选择" clearable style="width: 100%"> <el-select v-model="form.dataAstScreen" placeholder="请选择" clearable style="width: 100%">
<el-option label="智能助手" value="智能助手" /> <el-option label="智能助手" value="智能助手" />
@ -218,9 +229,9 @@ const filterNode = (value, data) => {
const columns = ref([ const columns = ref([
{ key: 0, label: `资产编号`, visible: true }, { key: 0, label: `资产编号`, visible: true },
{ key: 1, label: `来源系统`, visible: true }, { key: 1, label: `来源系统`, visible: true },
{ key: 2, label: `英文名称`, visible: true }, { key: 2, label: `英文名称`, visible: true },
{ key: 3, label: `中文名称`, visible: true }, { key: 3, label: `中文名称`, visible: true },
{ key: 4, label: `类型`, visible: true }, { key: 4, label: `类型`, visible: true },
{ key: 5, label: `资产标签`, visible: true }, { key: 5, label: `资产标签`, visible: true },
{ key: 6, label: `资产描述`, visible: true }, { key: 6, label: `资产描述`, visible: true },
{ key: 7, label: `资产应用场景`, visible: true }, { key: 7, label: `资产应用场景`, visible: true },
@ -382,8 +393,12 @@ const data = reactive({
rules: { rules: {
astNo: [{ required: true, message: "请输入", trigger: "blur" }], astNo: [{ required: true, message: "请输入", trigger: "blur" }],
dataAstEngName: [{ required: true, message: "请输入", trigger: "blur" }], dataAstEngName: [{ required: true, message: "请输入", trigger: "blur" }],
dataAstCnName: [{ required: true, message: "请输入", trigger: "blur" }],
dataAstType: [{ required: true, message: "请选择", trigger: "blur" }], dataAstType: [{ required: true, message: "请选择", trigger: "blur" }],
dataAstStat: [{ required: true, message: "请选择", trigger: "blur" }], dataAstStat: [{ required: true, message: "请选择", trigger: "blur" }],
dataAstSrc: [{ required: true, message: "请选择", trigger: "blur" }],
dataAstScreen: [{ required: false, message: "请选择", trigger: "blur" }],
dataAstScrenClas: [{ required: false, message: "请选择", trigger: "blur" }],
} }
}); });
const { form, rules } = toRefs(data); const { form, rules } = toRefs(data);
@ -399,8 +414,8 @@ function submitForm() {
"dataAstType": form.value.dataAstType, "dataAstType": form.value.dataAstType,
"dataAstStat": form.value.dataAstStat, "dataAstStat": form.value.dataAstStat,
"dataAstDesc": form.value.dataAstDesc, "dataAstDesc": form.value.dataAstDesc,
"dataAstScreen": form.value.dataAstScreen?form.value.dataAstScreen:"", "dataAstScreen": form.value.dataAstScreen || "", //
"dataAstScrenClas": form.value.dataAstScrenClas?form.value.dataAstScrenClas:"", "dataAstScrenClas": form.value.dataAstScrenClas || "", //
"dataAstClas": form.value.dataAstClas?form.value.dataAstClas:"", "dataAstClas": form.value.dataAstClas?form.value.dataAstClas:"",
"dataAstCont": form.value.dataAstCont?form.value.dataAstCont:"", "dataAstCont": form.value.dataAstCont?form.value.dataAstCont:"",
"dataAstFaq": form.value.dataAstFaq?form.value.dataAstFaq:"", "dataAstFaq": form.value.dataAstFaq?form.value.dataAstFaq:"",

Loading…
Cancel
Save