|  |  |  | from datetime import datetime | 
					
						
							|  |  |  | from sqlalchemy import case  | 
					
						
							|  |  |  | from sqlalchemy.orm import aliased | 
					
						
							|  |  |  | from sqlalchemy import delete, func, not_, select, update, or_, and_, desc | 
					
						
							|  |  |  | from sqlalchemy.ext.asyncio import AsyncSession | 
					
						
							|  |  |  | from sqlalchemy.exc import IntegrityError | 
					
						
							|  |  |  | from module_admin.entity.do.data_ast_content_do import DataAstContent,DataAstContentRela,DataAssetInfo,DataAstBookmarkRela,DataAstIndx | 
					
						
							|  |  |  | from module_admin.entity.do.user_do import SysUser | 
					
						
							|  |  |  | from module_admin.entity.vo.data_ast_content_vo import DataCatalogPageQueryModel, DeleteDataCatalogModel,DataCatalogChild,DataAstBookmarkRelaRequest,DataAstIndxRequest,DataAstIndxResponse | 
					
						
							|  |  |  | from utils.page_util import PageUtil | 
					
						
							|  |  |  | from utils.log_util import logger | 
					
						
							|  |  |  | from exceptions.exception import ServiceException | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class DataCatalogDAO: | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     数据目录管理模块数据库操作层 | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_catalog_by_id(cls, db: AsyncSession, content_onum: int): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据目录ID获取目录详细信息 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param content_onum: 目录ID | 
					
						
							|  |  |  |         :return: 目录信息对象 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         catalog_info = ( | 
					
						
							|  |  |  |             (await db.execute(select(DataAstContent).where(DataAstContent.content_onum == content_onum , DataAstContent.content_stat == 1))) | 
					
						
							|  |  |  |             .scalars() | 
					
						
							|  |  |  |             .first() | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return catalog_info | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_catalog_detail_by_info(cls, db: AsyncSession, catalog: DataCatalogPageQueryModel): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据目录参数获取目录信息 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 目录参数对象 | 
					
						
							|  |  |  |         :return: 目录信息对象 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         catalog_info = ( | 
					
						
							|  |  |  |             ( | 
					
						
							|  |  |  |                 await db.execute( | 
					
						
							|  |  |  |                     select(DataAstContent).where( | 
					
						
							|  |  |  |                         DataAstContent.content_name == catalog.content_name if catalog.content_name else True, | 
					
						
							|  |  |  |                         DataAstContent.content_stat == catalog.content_stat if catalog.content_stat else True, | 
					
						
							|  |  |  |                         DataAstContent.content_pic == catalog.content_pic if catalog.content_pic else True, | 
					
						
							|  |  |  |                         DataAstContent.content_stat == 1, | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             .scalars() | 
					
						
							|  |  |  |             .first() | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return catalog_info | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_catalog_list(cls, db: AsyncSession, query_object: DataCatalogPageQueryModel, user_id: int, user_name: str, is_page: bool = False): | 
					
						
							|  |  |  |         # 创建别名对象 | 
					
						
							|  |  |  |         t1 = aliased(DataAstContentRela, name='t1') | 
					
						
							|  |  |  |         t2 = aliased(DataAssetInfo, name='t2') | 
					
						
							|  |  |  |         t3 = aliased(DataAstBookmarkRela, name='t3') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 构建子查询1(对应subquery_t1) | 
					
						
							|  |  |  |         subquery_t1 = ( | 
					
						
							|  |  |  |             select(t1) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 t1.upd_prsn == user_name, | 
					
						
							|  |  |  |                 t1.content_onum == '2', | 
					
						
							|  |  |  |                 t1.rela_status == '1' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             .union_all( | 
					
						
							|  |  |  |                 select(t1) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     t1.content_onum != '2', | 
					
						
							|  |  |  |                     t1.rela_status == '1' | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ).alias('subquery_t1') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 新增子查询2(对应subquery_t2) | 
					
						
							|  |  |  |         subquery_t2 = ( | 
					
						
							|  |  |  |             select(t1.rela_onum) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 t1.rela_status == 1, | 
					
						
							|  |  |  |                 t1.upd_prsn == user_name, #query_object.upd_prsn | 
					
						
							|  |  |  |                 t1.content_onum.in_( | 
					
						
							|  |  |  |                     select(DataAstContent.content_onum) | 
					
						
							|  |  |  |                     .where( | 
					
						
							|  |  |  |                         or_( | 
					
						
							|  |  |  |                             DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |                             DataAstContent.content_onum == 2 | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         DataAstContent.content_stat == 1, | 
					
						
							|  |  |  |                         DataAstContent.upd_prsn == user_name | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ).alias('subquery_t2') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 主查询构建 | 
					
						
							|  |  |  |         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的属性,而非t2.c | 
					
						
							|  |  |  |                 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 != None, 1), | 
					
						
							|  |  |  |                     else_=0 | 
					
						
							|  |  |  |                 ).label('bookmark_flag'), | 
					
						
							|  |  |  |                 case( | 
					
						
							|  |  |  |                     (subquery_t2.c.rela_onum != None, 1), | 
					
						
							|  |  |  |                     else_=0 | 
					
						
							|  |  |  |                 ).label('sczc_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 | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  |             .outerjoin(subquery_t2, subquery_t1.c.rela_onum == subquery_t2.c.rela_onum) | 
					
						
							|  |  |  |             .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 check_duplicate_catalog(cls, db: AsyncSession, catalog1: dict, exclude_content_onum: int = None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         校验同一父节点下是否已存在相同名称的目录(可排除指定 content_onum) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         :param db: ORM 对象 | 
					
						
							|  |  |  |         :param catalog1: 主目录对象(DataAstContent) | 
					
						
							|  |  |  |         :param exclude_content_onum: 可选,编辑时排除自己 | 
					
						
							|  |  |  |         :return: 如果存在重复目录,抛出 ServiceException | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = select(DataAstContent).where( | 
					
						
							|  |  |  |             and_( | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum == catalog1.get("supr_content_onum"), | 
					
						
							|  |  |  |                 DataAstContent.content_name == catalog1.get("content_name") | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         if exclude_content_onum: | 
					
						
							|  |  |  |             query = query.where(DataAstContent.content_onum != exclude_content_onum) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         exist_catalog = result.scalars().first() | 
					
						
							|  |  |  |         if exist_catalog: | 
					
						
							|  |  |  |             raise ServiceException( | 
					
						
							|  |  |  |                 message=f"同一父节点下已存在名称为“{catalog1.get('content_name')}”的目录" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def add_catalog_dao(cls, db: AsyncSession, catalog1: dict, catalog2: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         新增目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 目录对象 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         db_catalog = DataAstContent(**catalog1) | 
					
						
							|  |  |  |         db.add(db_catalog) | 
					
						
							|  |  |  |         await db.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 处理子关系(统一转换为 ORM 模型) | 
					
						
							|  |  |  |         for child in catalog2.get('children', []): | 
					
						
							|  |  |  |             # 如果是 Pydantic 模型实例,先转换为字典 | 
					
						
							|  |  |  |             if isinstance(child, DataCatalogChild): | 
					
						
							|  |  |  |                 child_dict = child.model_dump() | 
					
						
							|  |  |  |             elif isinstance(child, dict): | 
					
						
							|  |  |  |                 child_dict = child | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise TypeError("不支持的子关系数据类型") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 创建 ORM 模型实例 | 
					
						
							|  |  |  |             processed_child = dict(child_dict) | 
					
						
							|  |  |  |             processed_child['content_onum'] = db_catalog.content_onum | 
					
						
							|  |  |  |             db_child = DataAstContentRela(**processed_child) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             db.add(db_child) | 
					
						
							|  |  |  |             await db.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return db_catalog | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def edit_catalog_leaf_dao(cls, db: AsyncSession, catalog: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑叶子节点目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         content_onum = catalog['content_onum'] | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == content_onum) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 leaf_node_flag=catalog['leaf_node_flag'] | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def edit_catalog_child_dao(cls, db: AsyncSession, catalog: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑目录数据库操作(子节点先删除再新增) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典(包含 children 列表) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         content_onum = catalog['content_onum'] | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         # ---------- 更新主目录 ---------- | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == content_onum) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_name=catalog['content_name'], | 
					
						
							|  |  |  |                 content_stat=catalog['content_stat'], | 
					
						
							|  |  |  |                 content_intr=catalog['content_intr'], | 
					
						
							|  |  |  |                 content_pic=catalog['content_pic'], | 
					
						
							|  |  |  |                 supr_content_onum=catalog['supr_content_onum'], | 
					
						
							|  |  |  |                 leaf_node_flag=catalog['leaf_node_flag'], | 
					
						
							|  |  |  |                 upd_prsn=catalog['upd_prsn'], | 
					
						
							|  |  |  |                 upd_time=datetime.now() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         # ---------- 删除原有子关系 ---------- | 
					
						
							|  |  |  |         delete_stmt = ( | 
					
						
							|  |  |  |             delete(DataAstContentRela) | 
					
						
							|  |  |  |             .where(DataAstContentRela.content_onum == content_onum) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute(delete_stmt) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         # ---------- 新增子关系 ---------- | 
					
						
							|  |  |  |         for child in catalog.get('children', []): | 
					
						
							|  |  |  |             child['content_onum'] = content_onum | 
					
						
							|  |  |  |             db_child = DataAstContentRela(**child) | 
					
						
							|  |  |  |             db.add(db_child) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |         # 更新叶子节点状态 | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def edit_catalog_dao(cls, db: AsyncSession, catalog1: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """ 
 | 
					
						
							|  |  |  |         content_onum = catalog1['content_onum'] | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == content_onum) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_name=catalog1['content_name'], | 
					
						
							|  |  |  |                 content_stat=catalog1['content_stat'], | 
					
						
							|  |  |  |                 content_intr=catalog1['content_intr'], | 
					
						
							|  |  |  |                 content_pic=catalog1['content_pic'], | 
					
						
							|  |  |  |                 supr_content_onum=catalog1['supr_content_onum'], | 
					
						
							|  |  |  |                 leaf_node_flag=catalog1['leaf_node_flag'], | 
					
						
							|  |  |  |                 upd_prsn=catalog1['upd_prsn'], | 
					
						
							|  |  |  |                 upd_time=datetime.now() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def delete_catalog_dao(cls, db: AsyncSession, catalog: DeleteDataCatalogModel): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         删除目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 目录对象 | 
					
						
							|  |  |  |         :content_stat=0 作废 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         content_onums = catalog.content_onums.split(',') | 
					
						
							|  |  |  |         logger.info(f"Updating DataAstContent with supr_content_onum in {content_onums}") | 
					
						
							|  |  |  |         await db.execute( | 
					
						
							|  |  |  |             update(DataAstContentRela) | 
					
						
							|  |  |  |             .where(DataAstContentRela.content_onum.in_(content_onums)) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 rela_status=0, | 
					
						
							|  |  |  |                 rela_eff_end_date=datetime.now() | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum.in_(content_onums)) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_stat=0, | 
					
						
							|  |  |  |                 upd_time=datetime.now() | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         logger.info("更新叶子节点标志成功") | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_data_asset_catalog_tree(cls, db: AsyncSession): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         获取数据资产树 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 异步会话对象 | 
					
						
							|  |  |  |         :return: 去重后的数据资产树数据 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # 创建别名对象 | 
					
						
							|  |  |  |         a = aliased(DataAssetInfo, name='a') | 
					
						
							|  |  |  |         b = aliased(DataAstContentRela, name='b') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 构建查询 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select( | 
					
						
							|  |  |  |                 a.data_ast_src, | 
					
						
							|  |  |  |                 a.data_ast_eng_name, | 
					
						
							|  |  |  |                 a.data_ast_cn_name, | 
					
						
							|  |  |  |                 a.ast_no, | 
					
						
							|  |  |  |                 case( | 
					
						
							|  |  |  |                     (b.ast_onum.isnot(None), 1), | 
					
						
							|  |  |  |                     else_=0 | 
					
						
							|  |  |  |                 ).label('rel_status') | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             .distinct() | 
					
						
							|  |  |  |             .select_from(a) | 
					
						
							|  |  |  |             .outerjoin(b, and_( | 
					
						
							|  |  |  |                 a.ast_no == b.ast_onum, | 
					
						
							|  |  |  |                 b.rela_status == 1 | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  |             .where(a.data_ast_stat == 1) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         rows = result.fetchall() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return rows | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def moved_catalog_instr_dao(cls, db: AsyncSession, moved_catalog_data: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # content_onum = moved_catalog_data['content_onum'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == moved_catalog_data['content_onum'] , DataAstContent.supr_content_onum == moved_catalog_data['supr_content_onum']) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 supr_content_onum=moved_catalog_data['supr_content_onum_after'], | 
					
						
							|  |  |  |                 upd_time=datetime.now() | 
					
						
							|  |  |  |         ) ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def merge_catalog_instr_dao(cls, db: AsyncSession, merge_catalog_data: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑目录数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典 | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stmt1 = ( | 
					
						
							|  |  |  |             update(DataAstContentRela) | 
					
						
							|  |  |  |             .where( DataAstContentRela.content_onum == merge_catalog_data['content_onum'] and DataAstContentRela.rela_status == 1 ) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_onum=merge_catalog_data['content_onum_after'], | 
					
						
							|  |  |  |                 rela_eff_begn_date=datetime.now() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute(stmt1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stmt2 = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == merge_catalog_data['content_onum'] , DataAstContent.supr_content_onum == merge_catalog_data['supr_content_onum']) | 
					
						
							|  |  |  |             .values( content_stat = '0' ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute(stmt2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         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: 更新的记录数量 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         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  # 重新抛出异常,由上层处理 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def moverel_data_ast_catalog_dao(cls, db: AsyncSession, moverel_catalog_data: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         编辑资产关系数据库操作  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 需要更新的目录字典  | 
					
						
							|  |  |  |         :return: | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContentRela) | 
					
						
							|  |  |  |             .where(DataAstContentRela.rela_onum == moverel_catalog_data['rela_onum'] , DataAstContentRela.content_onum == moverel_catalog_data['content_onum']) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_onum=moverel_catalog_data['content_onum_after'], | 
					
						
							|  |  |  |                 rela_eff_end_date=datetime.now() | 
					
						
							|  |  |  |         ) ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def update_leaf_node_flag(cls, db: AsyncSession): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         更新leaf_node_flag字段 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # 创建别名对象 | 
					
						
							|  |  |  |         t2 = aliased(DataAstContent, name='t2')  # 正确使用aliased创建别名 | 
					
						
							|  |  |  |         subquery = ( | 
					
						
							|  |  |  |             select(DataAstContent.content_onum) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContent.content_stat == '1', | 
					
						
							|  |  |  |                 DataAstContent.leaf_node_flag == 0, | 
					
						
							|  |  |  |                 not_( | 
					
						
							|  |  |  |                     select(1) | 
					
						
							|  |  |  |                     .select_from(t2)  # 使用别名后的表 | 
					
						
							|  |  |  |                     .where( | 
					
						
							|  |  |  |                         t2.supr_content_onum == DataAstContent.content_onum, | 
					
						
							|  |  |  |                         t2.content_stat == '1' | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     .exists()  # 添加exists()方法 | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ).alias('temp') | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContent) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum.in_(subquery)) | 
					
						
							|  |  |  |             .values(leaf_node_flag=1, upd_time=datetime.now()) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def delete_ast_book_mark_rela_dao(cls, db: AsyncSession, catalog: DataAstBookmarkRelaRequest, user_name: str, user_id: str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         取消收藏数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 收藏对象 | 
					
						
							|  |  |  |         :return: 操作结果字典(包含成功状态和提示信息) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             # 打印传入的参数 | 
					
						
							|  |  |  |             logger.info(f"开始处理取消收藏请求,传入参数:catalog={catalog}, user_name={user_name}, user_id={user_id}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 创建子查询:获取需要删除的资产编号 | 
					
						
							|  |  |  |             ast_onum_subquery = ( | 
					
						
							|  |  |  |                 select(DataAstContentRela.ast_onum) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContentRela.rela_onum == catalog['rela_onum'], | 
					
						
							|  |  |  |                     DataAstContentRela.upd_prsn == user_name, | 
					
						
							|  |  |  |                     DataAstContentRela.rela_status == '1' | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ).subquery() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # 创建子查询:获取在收藏目录下的序号content_onum | 
					
						
							|  |  |  |             content_onum_subquery = ( | 
					
						
							|  |  |  |                 select(DataAstContent.content_onum) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContent.content_onum == '2' or DataAstContent.supr_content_onum == '2', | 
					
						
							|  |  |  |                     DataAstContent.content_stat == '1', | 
					
						
							|  |  |  |                     DataAstContent.upd_prsn == user_name | 
					
						
							|  |  |  |                 ).subquery() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 创建子查询 | 
					
						
							|  |  |  |             content_onum_subquery = ( | 
					
						
							|  |  |  |                 select(DataAstContent.content_onum) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     and_( | 
					
						
							|  |  |  |                         or_( | 
					
						
							|  |  |  |                             DataAstContent.content_onum == '2', | 
					
						
							|  |  |  |                             DataAstContent.supr_content_onum == '2' | 
					
						
							|  |  |  |                         ), | 
					
						
							|  |  |  |                         DataAstContent.content_stat == '1', | 
					
						
							|  |  |  |                         DataAstContent.upd_prsn == user_name | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .subquery() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             # 打印子查询的SQL语句 | 
					
						
							|  |  |  |             logger.info(f"子查询SQL: {str(ast_onum_subquery),str(content_onum_subquery)}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 构建删除语句 | 
					
						
							|  |  |  |             stmt1 = ( | 
					
						
							|  |  |  |                 delete(DataAstContentRela) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContentRela.upd_prsn == user_name, | 
					
						
							|  |  |  |                     DataAstContentRela.rela_status == 1, | 
					
						
							|  |  |  |                     DataAstContentRela.content_onum.in_(content_onum_subquery), | 
					
						
							|  |  |  |                     DataAstContentRela.ast_onum.in_(ast_onum_subquery) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 打印删除语句1的SQL | 
					
						
							|  |  |  |             logger.info(f"删除语句1 SQL: {str(stmt1)}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             stmt2 = ( | 
					
						
							|  |  |  |                 delete(DataAstBookmarkRela) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstBookmarkRela.data_ast_no.in_(ast_onum_subquery), | 
					
						
							|  |  |  |                     DataAstBookmarkRela.user_id == user_id | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 打印删除语句2的SQL | 
					
						
							|  |  |  |             logger.info(f"删除语句2 SQL: {str(stmt2)}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 执行删除操作 | 
					
						
							|  |  |  |             logger.info("开始执行删除操作...") | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             await db.execute(stmt2) | 
					
						
							|  |  |  |             await db.execute(stmt1) | 
					
						
							|  |  |  |             await db.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             logger.info(f"成功删除收藏关系") | 
					
						
							|  |  |  |             return {"is_success": True} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except IntegrityError as ie: | 
					
						
							|  |  |  |             await db.rollback() | 
					
						
							|  |  |  |             logger.error(f"删除收藏关系失败(完整性错误): {str(ie)}") | 
					
						
							|  |  |  |             return {"is_success": False, "message": "数据库完整性错误"} | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             await db.rollback() | 
					
						
							|  |  |  |             logger.error(f"删除收藏关系失败: {str(e)}") | 
					
						
							|  |  |  |             return {"is_success": False, "message": "未知错误"} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def delete_ast_book_mark_rela_by_content_onum(cls, db: AsyncSession, content_onum: int, user_id: int): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据目录ID和用户ID删除收藏关系(修正CTE语法) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # 创建别名对象 | 
					
						
							|  |  |  |         t1 = aliased(DataAstContentRela, name='t1') | 
					
						
							|  |  |  |         t2 = aliased(DataAssetInfo, name='t2') | 
					
						
							|  |  |  |         t3 = aliased(DataAstBookmarkRela, name='t3') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 使用子查询替代CTE | 
					
						
							|  |  |  |         subquery = ( | 
					
						
							|  |  |  |             select(t3.rela_onum) | 
					
						
							|  |  |  |             .select_from(DataAstContent) | 
					
						
							|  |  |  |             .outerjoin(t1, DataAstContent.content_onum == t1.content_onum) | 
					
						
							|  |  |  |             .outerjoin(t2, t1.ast_onum == t2.ast_no) | 
					
						
							|  |  |  |             .outerjoin(t3, and_( | 
					
						
							|  |  |  |                 t2.data_ast_no == t3.data_ast_no, | 
					
						
							|  |  |  |                 t3.user_id == user_id | 
					
						
							|  |  |  |             )) | 
					
						
							|  |  |  |             .where(DataAstContent.content_onum == content_onum) | 
					
						
							|  |  |  |             .subquery() | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # 直接使用子查询构造DELETE语句 | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             delete(DataAstBookmarkRela) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstBookmarkRela.rela_onum.in_( | 
					
						
							|  |  |  |                     select(subquery.c.rela_onum) | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |         await db.commit() | 
					
						
							|  |  |  |         logger.info("删除收藏关系,操作成功") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def add_ast_book_mark_rela_dao(cls, db: AsyncSession, catalog: DataAstBookmarkRelaRequest, user_name: str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         添加收藏数据库操作 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param catalog: 收藏对象 | 
					
						
							|  |  |  |         :return: 操作结果字典(包含成功状态和提示信息) | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             logger.info(f"开始处理收藏请求,用户ID: {catalog['user_id']}, 资产编号: {catalog['data_ast_no']}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 获取通过资产序号,获取资产编号 | 
					
						
							|  |  |  |             para_ast_no = ( | 
					
						
							|  |  |  |                 select( | 
					
						
							|  |  |  |                     DataAssetInfo.ast_no | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAssetInfo.data_ast_no == catalog['data_ast_no'] | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             )             | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 1. 检查是否已存在相同收藏 | 
					
						
							|  |  |  |             logger.info("检查是否已存在相同收藏...") | 
					
						
							|  |  |  |             exists = await db.execute( | 
					
						
							|  |  |  |                 select(DataAstBookmarkRela) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstBookmarkRela.user_id == catalog['user_id'], | 
					
						
							|  |  |  |                     DataAstBookmarkRela.data_ast_no == para_ast_no | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             if exists.scalar(): | 
					
						
							|  |  |  |                 logger.warning(f"用户 {catalog['user_id']} 已收藏资产 {para_ast_no}") | 
					
						
							|  |  |  |                 return {"is_success": False, "message": "该资产已被收藏"} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 2. 获取当前最大顺序号 | 
					
						
							|  |  |  |             logger.info("获取当前最大顺序号...") | 
					
						
							|  |  |  |             max_order = await db.execute( | 
					
						
							|  |  |  |                 select(func.max(DataAstBookmarkRela.bookmark_orde)) | 
					
						
							|  |  |  |                 .where(DataAstBookmarkRela.user_id == catalog['user_id']) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             max_bookmark_orde = max_order.scalar() or 0 | 
					
						
							|  |  |  |             logger.info(f"当前最大顺序号: {max_bookmark_orde}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 3. 设置新顺序号 | 
					
						
							|  |  |  |             logger.info("设置新顺序号...") | 
					
						
							|  |  |  |             catalog_dict = { | 
					
						
							|  |  |  |                 'user_id': catalog["user_id"], | 
					
						
							|  |  |  |                 'data_ast_no': para_ast_no, | 
					
						
							|  |  |  |                 'bookmark_orde': max_bookmark_orde + 1, | 
					
						
							|  |  |  |                 'bookmark_time': datetime.now() | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 4. 创建并保存新记录 | 
					
						
							|  |  |  |             logger.info("创建并保存新记录...") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             db_catalog = DataAstBookmarkRela(**catalog_dict) | 
					
						
							|  |  |  |             db.add(db_catalog) | 
					
						
							|  |  |  |             # 添加收藏关系内容 | 
					
						
							|  |  |  |             logger.info("添加收藏关系内容...") | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             new_rela = DataAstContentRela( | 
					
						
							|  |  |  |                 content_onum=catalog["content_onum"], | 
					
						
							|  |  |  |                 ast_onum=para_ast_no, | 
					
						
							|  |  |  |                 rela_type=catalog["rela_type"], | 
					
						
							|  |  |  |                 rela_eff_begn_date=catalog["rela_eff_begn_date"], | 
					
						
							|  |  |  |                 rela_eff_end_date=catalog["rela_eff_end_date"], | 
					
						
							|  |  |  |                 upd_prsn=user_name, | 
					
						
							|  |  |  |                 rela_status="1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             db.add(new_rela) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 提交事务 | 
					
						
							|  |  |  |             logger.info("提交事务...") | 
					
						
							|  |  |  |             await db.flush() | 
					
						
							|  |  |  |             logger.info(f"用户 {catalog['user_id']} 收藏资产 {para_ast_no} 成功") | 
					
						
							|  |  |  |             return {"is_success": True, "message": "收藏成功"} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"收藏操作失败: {str(e)}", exc_info=True) | 
					
						
							|  |  |  |             await db.rollback() | 
					
						
							|  |  |  |             return {"is_success": False, "message": "收藏操作失败"} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_data_ast_indx_list(cls, db: AsyncSession, query_object: DataAstIndxRequest): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据查询参数获取数据资产指标列表 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select( | 
					
						
							|  |  |  |                 DataAstIndx.ast_no, | 
					
						
							|  |  |  |                 DataAstIndx.indx_no, | 
					
						
							|  |  |  |                 DataAstIndx.indx_name, | 
					
						
							|  |  |  |                 DataAstIndx.indx_val | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstIndx.ast_no == query_object.ast_no if query_object.ast_no else True, | 
					
						
							|  |  |  |                 DataAstIndx.indx_no == query_object.indx_no if query_object.indx_no else True, | 
					
						
							|  |  |  |                 DataAstIndx.indx_name.like(f"%{query_object.indx_name}%") if query_object.indx_name else True | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         rows = result.mappings().all()  # 直接获取字典列表 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return rows | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_bookmark_folder_by_name(cls, db: AsyncSession, folder_name: str, user_name: str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据名称和用户名获取收藏目录 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param folder_name: 目录名称 | 
					
						
							|  |  |  |         :param user_name: 用户名 | 
					
						
							|  |  |  |         :return: 目录对象 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select(DataAstContent) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContent.content_name == folder_name, | 
					
						
							|  |  |  |                 DataAstContent.upd_prsn == user_name, | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |                 DataAstContent.content_stat == "1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         return result.scalars().first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_bookmark_folder_by_id(cls, db: AsyncSession, content_onum: int, user_name: str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据ID和用户名获取收藏目录 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param content_onum: 目录ID | 
					
						
							|  |  |  |         :param user_name: 用户名 | 
					
						
							|  |  |  |         :return: 目录对象 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select(DataAstContent) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContent.content_onum == content_onum, | 
					
						
							|  |  |  |                 DataAstContent.upd_prsn == user_name, | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |                 DataAstContent.content_stat == "1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         return result.scalars().first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def check_folder_has_relations(cls, db: AsyncSession, content_onum: int): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         检查目录下是否有资产关系 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param content_onum: 目录ID | 
					
						
							|  |  |  |         :return: 是否存在关系 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select(func.count(DataAstContentRela.rela_onum)) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContentRela.content_onum == content_onum, | 
					
						
							|  |  |  |                 DataAstContentRela.rela_status == "1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         count = result.scalar() | 
					
						
							|  |  |  |         return count > 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_bookmark_folders(cls, db: AsyncSession, user_name: str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         获取用户的收藏目录列表 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param user_name: 用户名 | 
					
						
							|  |  |  |         :return: 目录列表 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         # 构建联合查询 | 
					
						
							|  |  |  |         combined_query = ( | 
					
						
							|  |  |  |             select( | 
					
						
							|  |  |  |                 DataAstContent.content_onum, | 
					
						
							|  |  |  |                 DataAstContent.content_name, | 
					
						
							|  |  |  |                 DataAstContent.content_intr, | 
					
						
							|  |  |  |                 DataAstContent.content_pic, | 
					
						
							|  |  |  |                 DataAstContent.upd_time, | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum, | 
					
						
							|  |  |  |                 DataAstContent.leaf_node_flag | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             # 根目录条件 | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContent.content_onum == 2, | 
					
						
							|  |  |  |                 DataAstContent.content_stat == "1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             # 合并子目录条件 | 
					
						
							|  |  |  |             .union_all( | 
					
						
							|  |  |  |                 select( | 
					
						
							|  |  |  |                     DataAstContent.content_onum, | 
					
						
							|  |  |  |                     DataAstContent.content_name, | 
					
						
							|  |  |  |                     DataAstContent.content_intr, | 
					
						
							|  |  |  |                     DataAstContent.content_pic, | 
					
						
							|  |  |  |                     DataAstContent.upd_time, | 
					
						
							|  |  |  |                     DataAstContent.supr_content_onum, | 
					
						
							|  |  |  |                     DataAstContent.leaf_node_flag | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContent.upd_prsn == user_name, | 
					
						
							|  |  |  |                     DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |                     DataAstContent.content_stat == "1" | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .order_by(DataAstContent.upd_time.desc()) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         result = await db.execute(combined_query) | 
					
						
							|  |  |  |         return [dict(row) for row in result.mappings().all()] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def get_bookmark_folder_by_name_exclude_id(cls, db: AsyncSession, folder_name: str, user_name: str, exclude_id: int): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         根据名称和用户名获取收藏目录,排除指定ID | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param folder_name: 目录名称 | 
					
						
							|  |  |  |         :param user_name: 用户名 | 
					
						
							|  |  |  |         :param exclude_id: 排除的目录ID | 
					
						
							|  |  |  |         :return: 目录对象 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         query = ( | 
					
						
							|  |  |  |             select(DataAstContent) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContent.content_name == folder_name, | 
					
						
							|  |  |  |                 DataAstContent.upd_prsn == user_name, | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |                 DataAstContent.content_stat == "1", | 
					
						
							|  |  |  |                 DataAstContent.content_onum != exclude_id | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         return result.scalars().first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def is_bookmark_folder(cls, db: AsyncSession, content_onum: int, user_name: str = None): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         检查目录是否是收藏目录或其子目录 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: 数据库会话 | 
					
						
							|  |  |  |         :param content_onum: 目录ID | 
					
						
							|  |  |  |         :param user_name: 用户名(如果需要验证所有权) | 
					
						
							|  |  |  |         :return: 是否是收藏目录 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         if content_onum == 2:  # "我的收藏"根目录 | 
					
						
							|  |  |  |             return True | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         query = select(DataAstContent).where( | 
					
						
							|  |  |  |             DataAstContent.content_onum == content_onum, | 
					
						
							|  |  |  |             DataAstContent.supr_content_onum == 2, | 
					
						
							|  |  |  |             DataAstContent.content_stat == "1" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         if user_name: | 
					
						
							|  |  |  |             query = query.where(DataAstContent.upd_prsn == user_name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         result = await db.execute(query) | 
					
						
							|  |  |  |         return result.scalars().first() is not None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def move_bookmark_asset_dao(cls, db: AsyncSession, moverel_catalog_data: dict): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         在收藏目录间移动资产的数据库操作 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         stmt = ( | 
					
						
							|  |  |  |             update(DataAstContentRela) | 
					
						
							|  |  |  |             .where( | 
					
						
							|  |  |  |                 DataAstContentRela.rela_onum == moverel_catalog_data['rela_onum'], | 
					
						
							|  |  |  |                 DataAstContentRela.content_onum == moverel_catalog_data['content_onum'], | 
					
						
							|  |  |  |                 DataAstContentRela.rela_status == "1" | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             .values( | 
					
						
							|  |  |  |                 content_onum=moverel_catalog_data['content_onum_after'], | 
					
						
							|  |  |  |                 upd_prsn=moverel_catalog_data['upd_prsn'], | 
					
						
							|  |  |  |                 rela_eff_end_date=datetime.now() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         await db.execute(stmt) | 
					
						
							|  |  |  |         await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							|  |  |  |     async def delete_bookmark_folder_dao(cls, db: AsyncSession, content_onum: int, user_name: str,user_id:str): | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         删除收藏目录及其资产关系的专用数据库操作 | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         :param db: orm对象 | 
					
						
							|  |  |  |         :param content_onum: 收藏目录ID | 
					
						
							|  |  |  |         :param user_name: 用户名(用于权限验证) | 
					
						
							|  |  |  |         :return: 操作结果字典 | 
					
						
							|  |  |  |         """
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             logger.info(f"开始删除用户 {user_name} 的收藏目录 {content_onum}") | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # 1. 验证目录是否存在且属于当前用户和收藏体系 | 
					
						
							|  |  |  |             folder_query = select(DataAstContent).where( | 
					
						
							|  |  |  |                 DataAstContent.content_onum == content_onum, | 
					
						
							|  |  |  |                 DataAstContent.upd_prsn == user_name,  # 确保只能删除自己的收藏目录 | 
					
						
							|  |  |  |                 DataAstContent.supr_content_onum == 2,  # 确保是收藏子目录 | 
					
						
							|  |  |  |                 DataAstContent.content_stat == '1' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             folder_result = await db.execute(folder_query) | 
					
						
							|  |  |  |             folder = folder_result.scalars().first() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             if not folder: | 
					
						
							|  |  |  |                 logger.warning(f"未找到用户 {user_name} 的收藏目录 {content_onum} 或无权限删除") | 
					
						
							|  |  |  |                 return {"success": False, "message": "收藏目录不存在或无权限删除"} | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # 创建子查询,获取符合条件的 ast_onum | 
					
						
							|  |  |  |             ast_onum_subs = ( | 
					
						
							|  |  |  |                 select(DataAstContentRela.ast_onum) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContentRela.content_onum == content_onum, | 
					
						
							|  |  |  |                     DataAstContentRela.rela_status == '1', | 
					
						
							|  |  |  |                     DataAstContentRela.upd_prsn == user_name | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .subquery() | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 删除收藏关系表数据 | 
					
						
							|  |  |  |             delete_stmt = ( | 
					
						
							|  |  |  |                 delete(DataAstBookmarkRela) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstBookmarkRela.data_ast_no.in_(ast_onum_subs), | 
					
						
							|  |  |  |                     DataAstBookmarkRela.user_id == user_id | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             # 执行删除操作 | 
					
						
							|  |  |  |             await db.execute(delete_stmt) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 2. 更新关联的资产关系状态 | 
					
						
							|  |  |  |             rela_update = await db.execute( | 
					
						
							|  |  |  |                 update(DataAstContentRela) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContentRela.content_onum == content_onum, | 
					
						
							|  |  |  |                     DataAstContentRela.upd_prsn == user_name, | 
					
						
							|  |  |  |                     DataAstContentRela.rela_status == '1' | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .values( | 
					
						
							|  |  |  |                     rela_status='0', | 
					
						
							|  |  |  |                     rela_eff_end_date=datetime.now() | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |             rela_count = rela_update.rowcount | 
					
						
							|  |  |  |             logger.info(f"已更新 {rela_count} 个资产关系状态") | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # 3. 更新目录状态为无效 | 
					
						
							|  |  |  |             folder_update = await db.execute( | 
					
						
							|  |  |  |                 update(DataAstContent) | 
					
						
							|  |  |  |                 .where( | 
					
						
							|  |  |  |                     DataAstContent.content_onum == content_onum, | 
					
						
							|  |  |  |                     DataAstContent.upd_prsn == user_name, | 
					
						
							|  |  |  |                     DataAstContent.content_stat == '1' | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |                 .values( | 
					
						
							|  |  |  |                     content_stat='0', | 
					
						
							|  |  |  |                     upd_time=datetime.now() | 
					
						
							|  |  |  |                 ) | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 4. 更新叶子节点标志 | 
					
						
							|  |  |  |             await cls.update_leaf_node_flag(db) | 
					
						
							|  |  |  |             await db.commit() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             logger.info(f"成功删除用户 {user_name} 的收藏目录 {content_onum}") | 
					
						
							|  |  |  |             return {"success": True, "message": "收藏目录删除成功"} | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         except Exception as e: | 
					
						
							|  |  |  |             logger.error(f"删除收藏目录时发生错误: {str(e)}", exc_info=True) | 
					
						
							|  |  |  |             return {"success": False, "message": f"删除操作出错: {str(e)}"} |