You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							772 lines
						
					
					
						
							31 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							772 lines
						
					
					
						
							31 KiB
						
					
					
				| from datetime import datetime | |
| from utils.log_util import logger | |
| from collections import defaultdict | |
| from pyecharts.options import LabelOpts, InitOpts | |
| from fastapi.responses import JSONResponse | |
| from pyecharts.charts import Pie, Bar, Page | |
| from pyecharts import options as opts | |
| from sqlalchemy.ext.asyncio import AsyncSession | |
| from exceptions.exception import ServiceException | |
| from module_admin.dao.data_ast_content_dao import DataCatalogDAO | |
| from module_admin.entity.vo.common_vo import CrudResponseModel | |
| from module_admin.entity.vo.data_ast_content_vo import DataCatalogRequest, DataCatalogResponse, DataCatalogPageQueryModel, DeleteDataCatalogModel,DataCatalogResponseWithChildren, DataAssetCatalogTreeResponse, DataAssetCatalogTreeNode,DataCatalogMovedRequest,DataCatalogMergeRequest,DataCatalogChild,DataCatalogMoverelRequest,DataAstBookmarkRelaRequest,DataAstIndxRequest | |
| from pyecharts.globals import CurrentConfig | |
| 
 | |
| 
 | |
| class DataCatalogService: | |
|     """ | |
|     数据目录管理模块服务层 | |
|     """ | |
| 
 | |
|     @classmethod | |
|     async def get_catalog_list_services( | |
|         cls, query_db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, user_name: str, is_page: bool = False | |
|     ): | |
|         """ | |
|         获取数据目录列表信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param query_object: 查询参数对象 | |
|         :param is_page: 是否开启分页 | |
|         :return: 数据目录列表信息对象 | |
|         """ | |
|         catalog_list_result = await DataCatalogDAO.get_catalog_list(query_db, query_object, user_id, user_name, is_page) | |
|          | |
|         # 按contentOnum分组 | |
|         grouped = defaultdict(list) | |
|         for item in catalog_list_result.rows: | |
|             grouped[item['contentOnum']].append(item) | |
|          | |
|         nodes = {}  # 存储所有处理后的节点 | |
|          | |
|         # 处理每个组,生成节点 | |
|         for content_onum, items in grouped.items(): | |
|             first_item = items[0] | |
|             is_leaf = first_item['leafNodeFlag'] == 1 | |
|             rela_onum = first_item['relaOnum'] is not None | |
|              | |
|             # 公共字段提取 | |
|             common_fields = { | |
|                 'contentOnum': first_item['contentOnum'], | |
|                 'contentName': first_item['contentName'], | |
|                 'contentStat': first_item['contentStat'], | |
|                 'contentIntr': first_item['contentIntr'], | |
|                 'contentPic': first_item['contentPic'], | |
|                 'suprContentOnum': first_item['suprContentOnum'], | |
|                 'leafNodeFlag': first_item['leafNodeFlag'], | |
|                 'updPrsn': first_item['updPrsn'], | |
|                 'updTime': first_item['updTime'], | |
|                 'children': [] | |
|             } | |
|              | |
|             # 处理叶子节点的数据资产子节点 | |
|             if is_leaf and rela_onum : | |
|                 for item in items: | |
|                      | |
|                     asset_child = { | |
|                         'relaOnum': item['relaOnum'], | |
|                         'contentOnum': first_item['contentOnum'], | |
|                         'astOnum': item['astOnum'], | |
|                         'relaType': item['relaType'], | |
|                         'relaEffBegnDate': item['relaEffBegnDate'], | |
|                         'relaEffEndDate': item['relaEffEndDate'], | |
|                         'updPrsn1': item['updPrsn1'], | |
|                         'dataAstNo': item['dataAstNo'], | |
|                         'dataAstEngName': item['dataAstEngName'], | |
|                         'dataAstCnName': item['dataAstCnName'] if item['dataAstCnName'] else item['dataAstEngName'], | |
|                         'dataAstType': item['dataAstType'], | |
|                         'dataAstStat': item['dataAstStat'], | |
|                         'dataAstDesc': item['dataAstDesc'], | |
|                         'dataAstClas': item['dataAstClas'], | |
|                         'dataAstCont': item['dataAstCont'], | |
|                         'dataAstFaq': item['dataAstFaq'], | |
|                         'dataAstEstbTime': item['dataAstEstbTime'], | |
|                         'dataAstUpdTime': item['dataAstUpdTime'], | |
|                         'dataAstSrc': item['dataAstSrc'], | |
|                         'astNo': item['astNo'], | |
|                         'bookmarkOrde': item['bookmarkOrde'], | |
|                         'bookmarkFlag': item['bookmarkFlag'], | |
|                         'sczcFlag': item['sczcFlag'] | |
|                     } | |
|                     common_fields['children'].append(asset_child) | |
|              | |
|             nodes[content_onum] = common_fields | |
|          | |
|         # 构建父子关系 | |
|         root = None | |
|         for content_onum, node in nodes.items(): | |
|             supr = node['suprContentOnum'] | |
|             if supr is None: | |
|                 root = node | |
|             else: | |
|                 parent = nodes.get(supr) | |
|                 if parent: | |
|                     parent['children'].append(node) | |
|         catalog_list_result.rows = [root] | |
| 
 | |
|         return catalog_list_result | |
| 
 | |
|     @classmethod | |
|     async def get_catalog_detail_services(cls, query_db: AsyncSession, content_onum: int): | |
|         """ | |
|         获取数据目录详细信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param content_onum: 数据目录ID | |
|         :return: 数据目录详细信息对象 | |
|         """ | |
|          | |
|         catalog_detail_result = await DataCatalogDAO.get_catalog_by_id(query_db, content_onum) | |
| 
 | |
|         return catalog_detail_result | |
| 
 | |
|     @classmethod | |
|     async def add_catalog_services(cls, query_db: AsyncSession, request: DataCatalogResponseWithChildren): | |
|         """ | |
|         新增数据目录信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param request: 新增数据目录请求对象 | |
|         :return: 新增目录操作结果 | |
|         """ | |
|         catalog_data1 = { | |
|             'content_name': request.content_name, | |
|             'content_stat': request.content_stat, | |
|             'content_intr': request.content_intr, | |
|             'content_pic': request.content_pic, | |
|             'supr_content_onum': request.supr_content_onum, | |
|             'leaf_node_flag': request.leaf_node_flag, | |
|             'upd_prsn': request.upd_prsn | |
|         } | |
|         catalog_data2 = { | |
|             'content_name': request.content_name, | |
|             'content_stat': request.content_stat, | |
|             'content_intr': request.content_intr, | |
|             'content_pic': request.content_pic, | |
|             'supr_content_onum': request.supr_content_onum, | |
|             'leaf_node_flag': request.leaf_node_flag, | |
|             'upd_prsn': request.upd_prsn, | |
|             'children': [child.model_dump() for child in request.children]  # 将 children 转换为字典列表 | |
|         } | |
| 
 | |
| 
 | |
|         try: | |
|             for child in catalog_data2["children"]: | |
|                 child["rela_eff_begn_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S"), # 设置默认值,当前时间 | |
|                 child["rela_eff_end_date"] = datetime(year=2999, month=12, day=31, hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S"), # 设置默认值,2999-12-31 | |
|                 child["upd_prsn"] = request.upd_prsn, | |
|                 child["rela_status"] = "1" | |
|             await DataCatalogDAO.check_duplicate_catalog(query_db, catalog_data1) | |
|             new_catalog = await DataCatalogDAO.add_catalog_dao(query_db, catalog_data1, catalog_data2) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='新增成功', data=new_catalog) | |
|         except ServiceException as e: | |
|             await query_db.rollback() | |
|             # 直接抛出,不再重新包装,保留 DAO 层信息 | |
|             raise e | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"创建目录时发生错误: {str(e)}") | |
| 
 | |
|     @classmethod | |
|     async def edit_catalog_leaf_services(cls, query_db: AsyncSession,content_onum : int, leaf_node_flag : int): | |
|         """ | |
|         编辑数据目录信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param request: 编辑数据目录请求对象 | |
|         :return: 编辑目录操作结果 | |
|         """ | |
|         catalog_data1 = { | |
|             'content_onum': content_onum, | |
|             'leaf_node_flag': leaf_node_flag | |
|         } | |
|         try: | |
|             await DataCatalogDAO.edit_catalog_leaf_dao(query_db, catalog_data1) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='更新成功') | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"更新目录时发生错误: {str(e)}") | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def edit_catalog_child_services(cls, query_db: AsyncSession, request: DataCatalogResponseWithChildren): | |
|         """ | |
|         编辑数据目录信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param request: 编辑数据目录请求对象 | |
|         :return: 编辑目录操作结果 | |
|         """ | |
|          | |
|         catalog_data = { | |
|             'content_onum': request.content_onum, | |
|             'content_name': request.content_name, | |
|             'content_stat': request.content_stat, | |
|             'content_intr': request.content_intr, | |
|             'content_pic': request.content_pic, | |
|             'supr_content_onum': request.supr_content_onum, | |
|             'leaf_node_flag': request.leaf_node_flag, | |
|             'upd_prsn': request.upd_prsn, | |
|             'children': [child.model_dump() for child in request.children]  # 将 children 转换为字典列表 | |
|         } | |
|          | |
|         try: | |
|             for child in catalog_data["children"]: | |
|                 # 设置 rela_eff_begn_date | |
|                 if child.get("rela_eff_begn_date"): | |
|                     child["rela_eff_begn_date"] = child["rela_eff_begn_date"].strftime("%Y-%m-%d %H:%M:%S") | |
|                 else: | |
|                     child["rela_eff_begn_date"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S") | |
|                  | |
|                 # 设置 rela_eff_end_date | |
|                 if child.get("rela_eff_end_date"): | |
|                     child["rela_eff_end_date"] = child["rela_eff_end_date"].strftime("%Y-%m-%d %H:%M:%S") | |
|                 else: | |
|                     child["rela_eff_end_date"] = datetime(year=2999, month=12, day=31, hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") | |
|                  | |
|                 child["upd_prsn"] = request.upd_prsn | |
|                 child["rela_status"] = "1" | |
|             await DataCatalogDAO.check_duplicate_catalog(query_db, catalog_data, exclude_content_onum=request.content_onum) | |
|             await DataCatalogDAO.edit_catalog_child_dao(query_db, catalog_data) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='更新成功') | |
|         except ServiceException as e: | |
|             await query_db.rollback() | |
|             # 直接抛出,不再重新包装,保留 DAO 层信息 | |
|             raise e         | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"更新目录时发生错误: {str(e)}") | |
| 
 | |
|     @classmethod | |
|     async def delete_catalog_services(cls, query_db: AsyncSession, request: DeleteDataCatalogModel,user_id): | |
|         """ | |
|         删除数据目录信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :param request: 删除数据目录请求对象 | |
|         :return: 删除目录操作结果 | |
|         """ | |
|         if request.content_onums: | |
|             content_onum_list = request.content_onums.split(',') | |
|             try: | |
|                 for content_onum in content_onum_list: | |
|                     catalog = await cls.get_catalog_detail_services(query_db, int(content_onum)) | |
|                     if not catalog: | |
|                         raise ServiceException(message=f'目录ID {content_onum} 不存在') | |
|                     await DataCatalogDAO.delete_catalog_dao(query_db, DeleteDataCatalogModel(content_onums=content_onum)) | |
|                     await DataCatalogDAO.delete_ast_book_mark_rela_by_content_onum(query_db, int(content_onum), user_id) | |
|                 await query_db.commit() | |
|                 return CrudResponseModel(is_success=True, message='删除成功') | |
|             except Exception as e: | |
|                 await query_db.rollback() | |
|                 raise e | |
|         else: | |
|             raise ServiceException(message='传入目录id为空') | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def get_data_asset_catalog_tree_services(cls, query_db: AsyncSession): | |
|         """ | |
|         获取数据资产树信息service | |
|  | |
|         :param query_db: orm对象 | |
|         :return: 数据资产树信息对象 | |
|         """ | |
|         # 从 DAO 层获取数据 | |
|         rows = await DataCatalogDAO.get_data_asset_catalog_tree(query_db) | |
|         # 使用字典暂存分组数据 | |
|         sys_groups = {} | |
| 
 | |
|         for item in rows: | |
|             sys_name, eng_name, cn_name, ast_no, rel_status = item | |
|             # 创建或获取系统分组 | |
|             if sys_name not in sys_groups: | |
|                 sys_groups[sys_name] = { | |
|                     "dataAssetSysName": sys_name, | |
|                     "children": [] | |
|                 } | |
|              | |
|             # 添加子节点 | |
|             sys_groups[sys_name]["children"].append({ | |
|                 "dataAssetCatalogNo": eng_name, | |
|                 "dataAssetCatalogName": cn_name if cn_name else eng_name, | |
|                 "dataAssetCatalogAstno": ast_no, | |
|                 "rel_status": rel_status | |
|             }) | |
|         results = list(sys_groups.values()) | |
|         # 转换为最终列表格式 | |
|         return  results | |
| 
 | |
|     @classmethod | |
|     async def moved_catalog_instr_services(cls, query_db: AsyncSession, request: DataCatalogMovedRequest): | |
| 
 | |
|         """ | |
|         移动数据目录service | |
|         """ | |
|                  | |
|         moved_catalog_data = { | |
|             'content_onum': request.content_onum, | |
|             'supr_content_onum': request.supr_content_onum, | |
|             'supr_content_onum_after': request.supr_content_onum_after | |
|         } | |
| 
 | |
|          | |
|         try: | |
|             await DataCatalogDAO.moved_catalog_instr_dao(query_db, moved_catalog_data) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='目录移动成功') | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"移动目录时发生错误: {str(e)}") | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def merge_catalog_instr_services(cls, query_db: AsyncSession, request: DataCatalogMergeRequest): | |
| 
 | |
|         """ | |
|         移动数据目录service | |
|         """ | |
|                  | |
|         merge_catalog_data = { | |
|             'content_onum': request.content_onum, | |
|             'supr_content_onum': request.supr_content_onum, | |
|             'content_onum_after': request.content_onum_after, | |
|             'supr_content_onum_after': request.supr_content_onum_after | |
|         } | |
|         try: | |
|             await DataCatalogDAO.merge_catalog_instr_dao(query_db, merge_catalog_data) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='目录合并成功') | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"目录合并时发生错误: {str(e)}") | |
|          | |
| 
 | |
|     @classmethod | |
|     async def removerel_data_ast_catalog_services(cls, query_db: AsyncSession, request: DataCatalogChild,user_name:str): | |
| 
 | |
|         """ | |
|         移除数据资产目录service | |
|         """ | |
|                  | |
|         removerel_catalog_data = { | |
|             'rela_onum': request.rela_onum, | |
|             'content_onum': request.content_onum, | |
|             'ast_onum': request.ast_onum, | |
|             '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': user_name, | |
|             'rela_status': request.rela_status | |
|         } | |
| 
 | |
|          | |
|         try: | |
|             await DataCatalogDAO.removerel_data_ast_catalog_dao(query_db, removerel_catalog_data) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='资产移除成功')         | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"移除资产时发生错误: {str(e)}") | |
| 
 | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def moverel_data_ast_catalog_services(cls, query_db: AsyncSession, request: DataCatalogMoverelRequest): | |
| 
 | |
|         """ | |
|         移动数据目录service | |
|         """ | |
|                  | |
|         moverel_catalog_data = { | |
|             'rela_onum': request.rela_onum, | |
|             'content_onum': request.content_onum, | |
|             'content_onum_after': request.content_onum_after | |
|         } | |
| 
 | |
|          | |
|         try: | |
|             await DataCatalogDAO.moverel_data_ast_catalog_dao(query_db, moverel_catalog_data) | |
|             await query_db.commit() | |
|             return CrudResponseModel(is_success=True, message='资产移动成功')         | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             raise ServiceException(message=f"资产移动时发生错误: {str(e)}") | |
| 
 | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def delete_ast_book_mark_rela_services(cls, db: AsyncSession, request: DataAstBookmarkRelaRequest, user_name: str, user_id: str): | |
|         """ | |
|         取消收藏数据库操作 | |
|  | |
|         """ | |
|         delete_rela_onum = { | |
|             'rela_onum': request.rela_onum | |
|             } | |
|         try: | |
|             await DataCatalogDAO.delete_ast_book_mark_rela_dao(db, delete_rela_onum,user_name,user_id) | |
|             await db.commit() | |
|             return CrudResponseModel(is_success=True, message='取消收藏,操作成功')    | |
|         except Exception as e: | |
|             await db.rollback() | |
|             logger.error(" 取消收藏,操作失败") | |
| 
 | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def add_ast_book_mark_rela_services(cls, db: AsyncSession, request: DataAstBookmarkRelaRequest, user_name: str): | |
|         """ | |
|         添加收藏数据库操作 | |
|  | |
|         :param db: 异步会话对象 | |
|         :param request: 收藏请求对象,包含用户ID、资产编号等信息 | |
|         :param user_name: 当前操作用户的名称 | |
|         :return: 标准化响应模型,包含操作是否成功、消息和返回数据 | |
|         """ | |
|         # 构建DAO参数 | |
|         add_rela_onum = { | |
|             'user_id': request.user_id, | |
|             'data_ast_no': request.data_ast_no,  # 我的收藏 | |
|             'content_onum': request.content_onum, | |
|             'rela_type': "归属关系", | |
|             'rela_eff_begn_date': datetime.now().strftime("%Y-%m-%d %H:%M:%S"),  # 设置默认值,当前时间 | |
|             'rela_eff_end_date': datetime(year=2999, month=12, day=31, hour=0, minute=0, second=0).strftime("%Y-%m-%d %H:%M:%S") | |
|         } | |
| 
 | |
|         try: | |
|             # 调用DAO层操作 | |
|             dao_result = await DataCatalogDAO.add_ast_book_mark_rela_dao(db, add_rela_onum, user_name) | |
| 
 | |
|             if not dao_result.get("is_success"): | |
|                 # 业务逻辑错误(如重复收藏) | |
|                 logger.warning(f"用户{request.user_id}收藏资产{request.data_ast_no}失败: {dao_result.get('message')}") | |
|                 return CrudResponseModel( | |
|                     is_success=False, | |
|                     message=dao_result.get("message", "操作失败"), | |
|                     data=None | |
|                 ) | |
| 
 | |
|             # 执行成功时提交事务 | |
|             await db.commit() | |
| 
 | |
|             # 记录成功日志 | |
|             if dao_result.get("data") is not None: | |
|                 logger.info(f"用户{request.user_id}收藏资产{request.data_ast_no}成功,顺序号: {dao_result.get('data').bookmark_orde}") | |
|                 return CrudResponseModel( | |
|                     is_success=True, | |
|                     message=dao_result.get("message", "操作成功"), | |
|                     data={ | |
|                         "rela_onum": dao_result.get("data").rela_onum, | |
|                         "bookmark_orde": dao_result.get("data").bookmark_orde | |
|                     } | |
|                 ) | |
|             else: | |
|                 logger.warning(f"用户{request.user_id}收藏资产{request.data_ast_no}失败: 返回数据为空") | |
|                 return CrudResponseModel( | |
|                     is_success=False, | |
|                     message="操作失败:返回数据为空", | |
|                     data=None | |
|                 ) | |
| 
 | |
|         except Exception as e: | |
|             await db.rollback() | |
|             logger.error( | |
|                 f"用户 {request.user_id} 收藏操作失败: {str(e)}",  # 直接使用 request.user_id | |
|                 exc_info=True | |
|             ) | |
|             return CrudResponseModel( | |
|                 is_success=False, | |
|                 message=f"收藏操作失败: {str(e)}" | |
|             ) | |
| 
 | |
| 
 | |
|     # 添加到 DataCatalogService 类中 | |
| 
 | |
|     @classmethod | |
|     async def add_bookmark_folder_services(cls, db: AsyncSession, folder: DataCatalogRequest): | |
|         """ | |
|         添加收藏子目录服务 | |
|          | |
|         :param db: 数据库会话 | |
|         :param folder: 目录请求对象 | |
|         :return: 操作结果 | |
|         """ | |
|         try: | |
|             # 检查是否已存在同名目录 | |
|             existing_folder = await DataCatalogDAO.get_bookmark_folder_by_name( | |
|                 db,  | |
|                 folder.content_name,  | |
|                 folder.upd_prsn | |
|             ) | |
|              | |
|             if existing_folder: | |
|                 return CrudResponseModel(is_success=False, message="已存在同名收藏目录") | |
|              | |
|             # 转换为字典并添加 | |
|             folder_dict = folder.model_dump(exclude_unset=True) | |
|             result = await DataCatalogDAO.add_catalog_dao(db, folder_dict, {"children": []}) | |
|              | |
|             # 提交事务 | |
|             await db.commit() | |
|              | |
|             return CrudResponseModel(is_success=True, message="收藏目录添加成功") | |
|         except Exception as e: | |
|             await db.rollback() | |
|             logger.error(f"添加收藏目录失败: {str(e)}", exc_info=True) | |
|             return CrudResponseModel(is_success=False, message=f"添加收藏目录失败: {str(e)}") | |
| 
 | |
|     @classmethod | |
|     async def edit_bookmark_folder_services(cls, db: AsyncSession, folder: DataCatalogRequest): | |
|         """ | |
|         修改收藏子目录服务 | |
|          | |
|         :param db: 数据库会话 | |
|         :param folder: 目录请求对象 | |
|         :return: 操作结果 | |
|         """ | |
|         try: | |
|             # 检查目录是否存在且属于当前用户 | |
|             existing_folder = await DataCatalogDAO.get_bookmark_folder_by_id( | |
|                 db,  | |
|                 folder.content_onum,  | |
|                 folder.upd_prsn | |
|             ) | |
|              | |
|             if not existing_folder: | |
|                 return CrudResponseModel(is_success=False, message="收藏目录不存在或无权限修改") | |
|              | |
|             # 检查是否已存在同名目录(排除自身) | |
|             same_name_folder = await DataCatalogDAO.get_bookmark_folder_by_name_exclude_id( | |
|                 db,  | |
|                 folder.content_name,  | |
|                 folder.upd_prsn, | |
|                 folder.content_onum | |
|             ) | |
|              | |
|             if same_name_folder: | |
|                 return CrudResponseModel(is_success=False, message="已存在同名收藏目录") | |
|              | |
|             # 转换为字典并更新 | |
|             folder_dict = folder.model_dump(exclude_unset=True) | |
|             folder_dict.update({ | |
|                 "supr_content_onum": 2,  # 确保父目录不变 | |
|                 "content_stat": "1",     # 添加状态字段 | |
|                 "leaf_node_flag": 1,     # 添加叶子节点标志 | |
|                 "content_intr": folder_dict.get("content_intr", None),  # 可选字段 | |
|                 "content_pic": folder_dict.get("content_pic", None)     # 可选字段 | |
|             }) | |
|              | |
|             await DataCatalogDAO.edit_catalog_dao(db, folder_dict) | |
|              | |
|             # 提交事务 | |
|             await db.commit() | |
|              | |
|             return CrudResponseModel(is_success=True, message="收藏目录修改成功") | |
|         except Exception as e: | |
|             await db.rollback() | |
|             logger.error(f"修改收藏目录失败: {str(e)}", exc_info=True) | |
|             return CrudResponseModel(is_success=False, message=f"修改收藏目录失败: {str(e)}") | |
| 
 | |
|     @classmethod | |
|     async def delete_bookmark_folder_services(cls, db: AsyncSession, content_onum: int, user_name: str,user_id:str): | |
|         """ | |
|         删除收藏子目录服务 | |
|          | |
|         :param db: 数据库会话 | |
|         :param content_onum: 目录ID | |
|         :param user_name: 用户名 | |
|         :return: 操作结果 | |
|         """ | |
|         try: | |
|             # 检查目录是否存在且属于当前用户 | |
|             existing_folder = await DataCatalogDAO.get_bookmark_folder_by_id( | |
|                 db,  | |
|                 content_onum,  | |
|                 user_name | |
|             ) | |
|              | |
|             if not existing_folder: | |
|                 return CrudResponseModel(is_success=False, message="收藏目录不存在或无权限删除") | |
|              | |
|              | |
|             # 使用专用方法执行删除操作 | |
|             delete_result = await DataCatalogDAO.delete_bookmark_folder_dao(db, content_onum, user_name,user_id) | |
|              | |
|             if not delete_result["success"]: | |
|                 return CrudResponseModel(is_success=False, message=delete_result["message"]) | |
|              | |
|             # 提交事务 | |
|             await db.commit() | |
|              | |
|             return CrudResponseModel(is_success=True, message="收藏目录删除成功") | |
|         except Exception as e: | |
|             await db.rollback() | |
|             logger.error(f"删除收藏目录失败: {str(e)}", exc_info=True) | |
|             return CrudResponseModel(is_success=False, message=f"删除收藏目录失败: {str(e)}") | |
| 
 | |
|     @classmethod | |
|     async def get_bookmark_folders_services(cls, db: AsyncSession, user_name: str): | |
|         """ | |
|         获取用户收藏目录列表服务 | |
|          | |
|         :param db: 数据库会话 | |
|         :param user_name: 用户名 | |
|         :return: 目录列表 | |
|         """ | |
|         try: | |
|             # 获取用户的收藏目录列表 | |
|             folders = await DataCatalogDAO.get_bookmark_folders(db, user_name) | |
|             return folders | |
|         except Exception as e: | |
|             logger.error(f"获取收藏目录列表失败: {str(e)}", exc_info=True) | |
|             return [] | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def move_bookmark_asset_services(cls, query_db: AsyncSession, request: DataCatalogMoverelRequest): | |
|         """ | |
|         在收藏目录间移动资产服务 | |
|         """ | |
|         try: | |
|             # 1. 验证源目录和目标目录是否都属于收藏体系 | |
|             source_is_bookmark = await DataCatalogDAO.is_bookmark_folder(query_db, request.content_onum, request.upd_prsn) | |
|             target_is_bookmark = await DataCatalogDAO.is_bookmark_folder( | |
|                 query_db,  | |
|                 request.content_onum_after,  | |
|                 request.upd_prsn | |
|             ) | |
|              | |
|             if not source_is_bookmark: | |
|                 return CrudResponseModel(is_success=False, message="源目录不是收藏目录") | |
|                  | |
|             if not target_is_bookmark: | |
|                 return CrudResponseModel(is_success=False, message="目标目录不是收藏目录或不属于当前用户") | |
|              | |
|             # 2. 构建移动数据 | |
|             moverel_catalog_data = { | |
|                 'rela_onum': request.rela_onum, | |
|                 'content_onum': request.content_onum, | |
|                 'content_onum_after': request.content_onum_after, | |
|                 'upd_prsn': request.upd_prsn | |
|             } | |
|              | |
|             # 3. 执行移动操作 | |
|             await DataCatalogDAO.move_bookmark_asset_dao(query_db, moverel_catalog_data) | |
|             await query_db.commit() | |
|              | |
|             return CrudResponseModel(is_success=True, message="收藏资产移动成功") | |
|              | |
|         except Exception as e: | |
|             await query_db.rollback() | |
|             logger.error(f"移动收藏资产失败: {str(e)}", exc_info=True) | |
|             return CrudResponseModel(is_success=False, message=f"移动收藏资产失败: {str(e)}") | |
| 
 | |
| 
 | |
|     @classmethod | |
|     async def get_data_ast_indx_list_services(cls, query_db: AsyncSession, query_object: DataAstIndxRequest): | |
|         """获取数据资产指标列表信息service""" | |
|         try: | |
|             indx_list_dict = await DataCatalogDAO.get_data_ast_indx_list(query_db, query_object) | |
|             indx_names = [item["indx_name"] for item in indx_list_dict] | |
|             indx_vals = [item["indx_val"] for item in indx_list_dict] | |
|             CurrentConfig.ONLINE_HOST = "/assets/js/" | |
| 
 | |
|             # 创建独立图表 | |
|             pie = ( | |
|                 Pie(init_opts=InitOpts(width="100%", height="180px")) | |
|                 .add("", list(zip(indx_names, indx_vals))) | |
|                 .set_global_opts( | |
|                     title_opts=opts.TitleOpts(title="指标饼图", padding=[5,0,0,0]), | |
|                     legend_opts=opts.LegendOpts( | |
|                         type_="scroll",  | |
|                         orient="vertical", | |
|                         pos_right="2%", | |
|                         pos_top="10%" | |
|                     ) | |
|                 ) | |
|                 .set_series_opts(label_opts=LabelOpts(formatter="{b}: {c}")) | |
|             ) | |
| 
 | |
|             bar = ( | |
|                 Bar(init_opts=InitOpts(width="100%", height="250px")) | |
|                 .add_xaxis(indx_names) | |
|                 .add_yaxis("指标值", indx_vals) | |
|                 .set_global_opts( | |
|                     title_opts=opts.TitleOpts(title="指标柱状图", padding=[20,0,0,0]), | |
|                     datazoom_opts=[opts.DataZoomOpts(type_="inside")] | |
|                 ) | |
|             ) | |
| 
 | |
|             # 生成独立图表HTML | |
|             pie_html = pie.render_embed() | |
|             bar_html = bar.render_embed() | |
| 
 | |
|             # 构建最终HTML结构 | |
|             responsive_html = f""" | |
|             <!DOCTYPE html> | |
|             <html> | |
|             <head> | |
|                 <meta charset="UTF-8"> | |
|                 <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
|                 <script type="text/javascript" src="/assets/js/echarts.min.js"></script> | |
|                 <style> | |
|                     html, body {{ | |
|                         margin: 0; | |
|                         padding: 0; | |
|                         width: 100%; | |
|                         height: 100%; | |
|                     }} | |
|                     .chart-container {{ | |
|                         width: 100%; | |
|                         height: 400px; /* 总高度根据实际需求调整 */ | |
|                     }} | |
|                     .echarts {{ | |
|                         width: 100% !important; | |
|                         height: 180px !important; | |
|                     }} | |
|                 </style> | |
|             </head> | |
|             <body> | |
|                 <div class="chart-container"> | |
|                     {pie_html} | |
|                     <br /> | |
|                     {bar_html} | |
|                     <br /> | |
|                 </div> | |
|                 <script> | |
|                     document.addEventListener('DOMContentLoaded', function() {{ | |
|                         // 统一初始化图表尺寸 | |
|                         const charts = document.querySelectorAll('[id^="chart_"]'); | |
|                         charts.forEach(chartDiv => {{ | |
|                             chartDiv.style.width = '100%'; | |
|                             chartDiv.style.height = '180px'; | |
|                         }}); | |
|                          | |
|                         // 响应式处理 | |
|                         function resizeCharts() {{ | |
|                             charts.forEach(chartDiv => {{ | |
|                                 const chart = echarts.getInstanceByDom(chartDiv); | |
|                                 chart && chart.resize(); | |
|                             }}); | |
|                         }} | |
|                         window.addEventListener('resize', resizeCharts); | |
|                         resizeCharts(); | |
|                     }}); | |
|                 </script> | |
|             </body> | |
|             </html> | |
|             """ | |
| 
 | |
|         except Exception as e: | |
|             logger.error(f"获取数据资产指标列表信息失败: {str(e)}") | |
|             raise ServiceException(message=f"获取数据资产指标列表信息失败: {str(e)}") | |
|         else: | |
|             return responsive_html
 | |
| 
 |