From b89073f4dacb3badb6f73a6e7653460c6d64d2c0 Mon Sep 17 00:00:00 2001 From: xueyinfei <1207092115@qq.com> Date: Fri, 25 Jul 2025 22:09:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E8=B5=84=E4=BA=A7=E5=8F=91?= =?UTF-8?q?=E5=B8=83=E5=90=8E=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/data_asset_controller.py | 56 +++++- .../controller/data_ast_content_controller.py | 5 +- .../module_admin/dao/data_asset_dao.py | 18 +- .../module_admin/dao/data_ast_content_dao.py | 159 ++++++------------ .../module_admin/dao/dataast_dao.py | 155 +++++++++++++++++ .../module_admin/entity/do/dataast_do.py | 67 ++++++++ .../module_admin/entity/vo/data_asset_vo.py | 16 +- .../module_admin/entity/vo/dataast_vo.py | 69 ++++++++ .../module_admin/service/approval_service.py | 36 +++- .../service/data_ast_content_service.py | 6 +- .../module_admin/service/dataast_service.py | 70 ++++++++ .../src/views/dataAsset/assetDetail/index.vue | 31 +++- 12 files changed, 558 insertions(+), 130 deletions(-) create mode 100644 vue-fastapi-backend/module_admin/dao/dataast_dao.py create mode 100644 vue-fastapi-backend/module_admin/entity/do/dataast_do.py create mode 100644 vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py create mode 100644 vue-fastapi-backend/module_admin/service/dataast_service.py 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 daedc26..dc5d8b6 100644 --- a/vue-fastapi-backend/module_admin/controller/data_asset_controller.py +++ b/vue-fastapi-backend/module_admin/controller/data_asset_controller.py @@ -1,9 +1,13 @@ from fastapi import APIRouter, Depends, Form, Request from sqlalchemy.ext.asyncio import AsyncSession 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.service.login_service import LoginService 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 utils.log_util import logger from utils.page_util import PageResponseModel @@ -144,4 +148,54 @@ async def export_data_assets( excel_data = await DataAssetService.export_data_asset_list_services(data_assets) logger.info('导出成功') - return ResponseUtil.streaming(data=bytes2file_response(excel_data)) \ No newline at end of file + 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) \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py b/vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py index f588f08..3b19149 100644 --- a/vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py +++ b/vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py @@ -198,8 +198,9 @@ async def removerel_data_ast_catalog( query_db: AsyncSession = Depends(get_db), 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) # 返回标准化响应 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 9f096fc..28f6f3d 100644 --- a/vue-fastapi-backend/module_admin/dao/data_asset_dao.py +++ b/vue-fastapi-backend/module_admin/dao/data_asset_dao.py @@ -1,6 +1,7 @@ from sqlalchemy import select, update, delete, insert from sqlalchemy.ext.asyncio import AsyncSession 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 utils.page_util import PageUtil from typing import List, Dict, Any @@ -82,6 +83,8 @@ class DataAssetDao: ) return result.rowcount + + @classmethod async def delete_data_asset(cls, db: AsyncSession, ast_no: str): """ @@ -91,11 +94,24 @@ class DataAssetDao: :param ast_no: 资产编号 :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( delete(DataAssetInfo) .where(DataAssetInfo.ast_no == ast_no) ) - return result.rowcount + + # 提交事务 + await db.commit() + + return result.rowcount + @classmethod async def get_data_asset_sources(cls, db: AsyncSession): """ diff --git a/vue-fastapi-backend/module_admin/dao/data_ast_content_dao.py b/vue-fastapi-backend/module_admin/dao/data_ast_content_dao.py index 9f6e97a..423d591 100644 --- a/vue-fastapi-backend/module_admin/dao/data_ast_content_dao.py +++ b/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 async def get_catalog_list(cls, db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, user_name: str, is_page: bool = False): @@ -530,26 +445,54 @@ class DataCatalogDAO: await cls.update_leaf_node_flag(db) + @classmethod async def removerel_data_ast_catalog_dao(cls, db: AsyncSession, removerel_catalog_data: dict): """ 编辑资产关系数据库操作 + 当删除目录下某个子资产时,要更新该用户收藏的其他资产关系, :param db: orm对象 :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 = ( + update(DataAstContentRela) + .where(DataAstContentRela.rela_onum.in_(rela_onum_list)) + .values(rela_status=removerel_catalog_data['rela_status']) + ) + await db.execute(stmt) + 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 # 重新抛出异常,由上层处理 - stmt = ( - update(DataAstContentRela) - .where(DataAstContentRela.rela_onum == removerel_catalog_data['rela_onum'] , DataAstContentRela.content_onum == removerel_catalog_data['content_onum']) - .values( - rela_status=removerel_catalog_data['rela_status'] - ) ) - - await db.execute(stmt) - await cls.update_leaf_node_flag(db) - @classmethod async def moverel_data_ast_catalog_dao(cls, db: AsyncSession, moverel_catalog_data: dict): @@ -705,20 +648,15 @@ class DataCatalogDAO: @classmethod async def delete_ast_book_mark_rela_by_content_onum(cls, db: AsyncSession, content_onum: int, user_id: int): """ - 根据目录ID和用户ID删除收藏关系 - - :param db: orm对象 - :param content_onum: 目录ID - :param user_id: 用户ID - :return: + 根据目录ID和用户ID删除收藏关系(修正CTE语法) """ # 创建别名对象 t1 = aliased(DataAstContentRela, name='t1') t2 = aliased(DataAssetInfo, name='t2') t3 = aliased(DataAstBookmarkRela, name='t3') - - cte = ( + # 使用子查询替代CTE + subquery = ( select(t3.rela_onum) .select_from(DataAstContent) .outerjoin(t1, DataAstContent.content_onum == t1.content_onum) @@ -728,17 +666,22 @@ class DataCatalogDAO: t3.user_id == user_id )) .where(DataAstContent.content_onum == content_onum) - ).cte('cte') + .subquery() + ) + # 直接使用子查询构造DELETE语句 stmt = ( 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.commit() - logger.info(" 删除收藏关系,操作成功") - + logger.info("删除收藏关系,操作成功") @classmethod diff --git a/vue-fastapi-backend/module_admin/dao/dataast_dao.py b/vue-fastapi-backend/module_admin/dao/dataast_dao.py new file mode 100644 index 0000000..e231032 --- /dev/null +++ b/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) \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/entity/do/dataast_do.py b/vue-fastapi-backend/module_admin/entity/do/dataast_do.py new file mode 100644 index 0000000..1b381a8 --- /dev/null +++ b/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='更新时间') \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/entity/vo/data_asset_vo.py b/vue-fastapi-backend/module_admin/entity/vo/data_asset_vo.py index d59b37f..a43b4c4 100644 --- a/vue-fastapi-backend/module_admin/entity/vo/data_asset_vo.py +++ b/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_stat: str = Field(default=None, alias="dataAstStat", 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_cont: str = Field(default=None, alias="dataAstCont", description='数据资产内容') - data_ast_faq: str = Field(default=None, alias="dataAstFaq", description='数据资产常见问题') + data_ast_cont: Optional[str] = Field(default=None, alias="dataAstCont", 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='数据资产来源(必填)') version_no: str = Field(default="1", alias="versionNo", description='版本号(默认最新)') ctrl_flag: str = Field(default=None, alias="ctrlFlag", description='操作类型 1:插入 2:删除 3:更新') diff --git a/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py b/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py new file mode 100644 index 0000000..3a941fc --- /dev/null +++ b/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] \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/service/approval_service.py b/vue-fastapi-backend/module_admin/service/approval_service.py index 6c65aa2..32943da 100644 --- a/vue-fastapi-backend/module_admin/service/approval_service.py +++ b/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.meta_dao import MetaDao 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 + class ApprovalService: """ 智能问答服务层 @@ -99,7 +102,10 @@ class ApprovalService: await cls.syncStdDictInfo(result_db, flow_approval.businessId, edit.status) # 标准代码审批 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 result_db.commit() return CrudResponseModel(is_success=True, message='操作成功') @@ -229,8 +235,32 @@ class ApprovalService: await DataStdDao.update_std_code_appr(result_db, main_appro_model.model_dump(exclude_unset=True)) 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 async def get_flow_list_services(cls, query_db: AsyncSession, query_param: ApprovalQueryObject, current_user: CurrentUserModel): diff --git a/vue-fastapi-backend/module_admin/service/data_ast_content_service.py b/vue-fastapi-backend/module_admin/service/data_ast_content_service.py index 43b109b..514b549 100644 --- a/vue-fastapi-backend/module_admin/service/data_ast_content_service.py +++ b/vue-fastapi-backend/module_admin/service/data_ast_content_service.py @@ -31,7 +31,7 @@ class DataCatalogService: :return: 数据目录列表信息对象 """ catalog_list_result = await DataCatalogDAO.get_catalog_list(query_db, query_object, user_id, user_name, is_page) - print('获取数据清单内容111:',catalog_list_result) + # 按contentOnum分组 grouped = defaultdict(list) for item in catalog_list_result.rows: @@ -342,7 +342,7 @@ class DataCatalogService: @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 @@ -355,7 +355,7 @@ class DataCatalogService: 'rela_type': request.rela_type, 'rela_eff_begn_date': request.rela_eff_begn_date, 'rela_eff_end_date': request.rela_eff_end_date, - 'upd_prsn': request.upd_prsn, + 'upd_prsn': user_name, 'rela_status': request.rela_status } diff --git a/vue-fastapi-backend/module_admin/service/dataast_service.py b/vue-fastapi-backend/module_admin/service/dataast_service.py new file mode 100644 index 0000000..e25088c --- /dev/null +++ b/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) \ No newline at end of file diff --git a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue index f26fe54..2a6d842 100644 --- a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue +++ b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue @@ -115,6 +115,17 @@ + + + + + + + + + + + - + @@ -218,9 +229,9 @@ const filterNode = (value, data) => { const columns = ref([ { key: 0, label: `资产编号`, visible: true }, { key: 1, label: `来源系统`, visible: true }, - { key: 2, label: `英文名称`, visible: true }, - { key: 3, label: `中文名称`, visible: true }, - { key: 4, label: `类型`, visible: true }, + { key: 2, label: `表英文名称`, visible: true }, + { key: 3, label: `表中文名称`, visible: true }, + { key: 4, label: `表类型`, visible: true }, { key: 5, label: `资产标签`, visible: true }, { key: 6, label: `资产描述`, visible: true }, { key: 7, label: `资产应用场景`, visible: true }, @@ -382,8 +393,12 @@ const data = reactive({ rules: { astNo: [{ required: true, message: "请输入", trigger: "blur" }], dataAstEngName: [{ required: true, message: "请输入", trigger: "blur" }], + dataAstCnName: [{ required: true, message: "请输入", trigger: "blur" }], dataAstType: [{ 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); @@ -399,8 +414,8 @@ function submitForm() { "dataAstType": form.value.dataAstType, "dataAstStat": form.value.dataAstStat, "dataAstDesc": form.value.dataAstDesc, - "dataAstScreen": form.value.dataAstScreen?form.value.dataAstScreen:"", - "dataAstScrenClas": form.value.dataAstScrenClas?form.value.dataAstScrenClas:"", + "dataAstScreen": form.value.dataAstScreen || "", // 添加默认值 + "dataAstScrenClas": form.value.dataAstScrenClas || "", // 添加默认值 "dataAstClas": form.value.dataAstClas?form.value.dataAstClas:"", "dataAstCont": form.value.dataAstCont?form.value.dataAstCont:"", "dataAstFaq": form.value.dataAstFaq?form.value.dataAstFaq:"",