diff --git a/vue-fastapi-backend/module_admin/controller/data_asset_controller.py b/vue-fastapi-backend/module_admin/controller/data_asset_controller.py index dc5d8b6..65c3211 100644 --- a/vue-fastapi-backend/module_admin/controller/data_asset_controller.py +++ b/vue-fastapi-backend/module_admin/controller/data_asset_controller.py @@ -193,9 +193,9 @@ async def add_dataast_appr( ) async def get_ast_main_appr_list( request: Request, - main_page_query: DataAstApprModel= Depends(DataAstApprModel), + flowId: str, query_db: AsyncSession = Depends(get_db), ): - main_page_query_result = await DataAstService.get_ast_main_appr_list(query_db, main_page_query, is_page=True) + main_page_query_result = await DataAstService.get_ast_main_appr_list(query_db, flowId, is_page=True) logger.info('获取数据标准列表成功') return ResponseUtil.success(data=main_page_query_result) \ No newline at end of file diff --git a/vue-fastapi-backend/module_admin/dao/dataast_dao.py b/vue-fastapi-backend/module_admin/dao/dataast_dao.py index e231032..b6a7e34 100644 --- a/vue-fastapi-backend/module_admin/dao/dataast_dao.py +++ b/vue-fastapi-backend/module_admin/dao/dataast_dao.py @@ -1,4 +1,4 @@ -from sqlalchemy import delete, select, update, desc,or_,not_,insert,and_,func +from sqlalchemy import delete, select, update, desc,or_,not_,insert,and_,text from sqlalchemy.ext.asyncio import AsyncSession from module_admin.entity.do.dataast_do import DataAssetInfoAppr from module_admin.entity.do.data_ast_content_do import DataAssetInfo @@ -55,87 +55,208 @@ class DataAstDao: + + @classmethod async def add_dataast_data(cls, db: AsyncSession, model: DataAstInfoModel): - # 子查询:获取每个 ast_no 对应的最新已成功审批版本 - subquery = ( - select( - DataAssetInfoAppr.ast_no, - func.max(DataAssetInfoAppr.version_no).label("max_version") - ) - .filter( - DataAssetInfoAppr.approStatus == "succeed" - ) - .group_by(DataAssetInfoAppr.ast_no) - .subquery() - ) - - # 主查询:筛选符合条件的记录并映射到目标模型 - query = ( - select(DataAssetInfoAppr) - .join( - subquery, - and_( - DataAssetInfoAppr.ast_no == subquery.c.ast_no, - DataAssetInfoAppr.version_no == subquery.c.max_version + try: + # 构建 SQL 语句 + upsert_sql = text(""" + INSERT INTO t_data_ast_info ( + data_ast_eng_name, + data_ast_cn_name, + data_ast_type, + data_ast_stat, + data_ast_desc, + data_ast_screen, + data_ast_scren_clas, + data_ast_cont, + data_ast_faq, + data_ast_estb_time, + data_ast_upd_time, + data_ast_src, + ast_no, + data_ast_clas + ) VALUES ( + :data_ast_eng_name, + :data_ast_cn_name, + :data_ast_type, + :data_ast_stat, + :data_ast_desc, + :data_ast_screen, + :data_ast_scren_clas, + :data_ast_cont, + :data_ast_faq, + :data_ast_estb_time, + :data_ast_upd_time, + :data_ast_src, + :ast_no, + :data_ast_clas ) - ) - .filter( - DataAssetInfoAppr.data_ast_stat == "1", - DataAssetInfoAppr.changeType == "add", - DataAssetInfoAppr.approStatus == "succeed" - ) - ) + ON DUPLICATE KEY UPDATE + data_ast_eng_name = VALUES(data_ast_eng_name), + data_ast_cn_name = VALUES(data_ast_cn_name), + data_ast_type = VALUES(data_ast_type), + data_ast_stat = VALUES(data_ast_stat), + data_ast_desc = VALUES(data_ast_desc), + data_ast_screen = VALUES(data_ast_screen), + data_ast_scren_clas = VALUES(data_ast_scren_clas), + data_ast_cont = VALUES(data_ast_cont), + data_ast_faq = VALUES(data_ast_faq), + data_ast_estb_time = VALUES(data_ast_estb_time), + data_ast_upd_time = VALUES(data_ast_upd_time), + data_ast_src = VALUES(data_ast_src), + data_ast_clas = VALUES(data_ast_clas); + """) - # 执行查询获取符合条件的记录 - approved_records = await db.scalars(query) - - # 收集需要处理的记录数据 - records_to_upsert = [] - for record in approved_records: - # 从源记录中提取需要的字段 - asset_data = { - "data_ast_eng_name": record.data_ast_eng_name, - "data_ast_cn_name": record.data_ast_cn_name, - "data_ast_type": record.data_ast_type, - "data_ast_stat": record.data_ast_stat, - "data_ast_desc": record.data_ast_desc, - "data_ast_screen": record.data_ast_screen, - "data_ast_scren_clas": record.data_ast_scren_clas, - "data_ast_cont": record.data_ast_cont, - "data_ast_faq": record.data_ast_faq, - "data_ast_estb_time": record.data_ast_estb_time, - "data_ast_upd_time": datetime.now(), # 使用当前时间 - "data_ast_src": record.data_ast_src, - "ast_no": record.ast_no, - "data_ast_clas": record.data_ast_clas - } - records_to_upsert.append(asset_data) - - # 使用 bulk_insert_mappings 执行批量插入/更新 - if records_to_upsert: - from sqlalchemy.dialects.mysql import insert - - insert_stmt = insert(DataAssetInfo).values(records_to_upsert) - - # 定义 ON DUPLICATE KEY UPDATE 子句 - update_dict = { - c.name: insert_stmt.inserted[c.name] - for c in DataAssetInfo.__table__.columns - if c.name != 'data_ast_no' and c.name != 'ast_no' # 排除主键和业务主键 - } - # 手动设置 upd_time 为当前时间 - update_dict['data_ast_upd_time'] = datetime.now() - - upsert_stmt = insert_stmt.on_duplicate_key_update(update_dict) + model_dict = model.model_dump() + model_dict['data_ast_upd_time'] = datetime.now() + + # 执行 UPSERT 操作 + await db.execute(upsert_sql, model_dict) + + # 提交事务 + await db.commit() + + return "元数据成功发布到数据资产!" + + except Exception as e: + # 出现异常时回滚事务 + await db.rollback() + raise e + # async def add_dataast_data(cls, db: AsyncSession, model: DataAstInfoModel): + # try: + # # 动态SQL:更新目标表中已存在的记录 + # update_sql = text(""" + # UPDATE t_data_ast_info target + # JOIN ( + # SELECT + # appr.data_ast_eng_name, + # appr.data_ast_cn_name, + # appr.data_ast_type, + # appr.data_ast_stat, + # appr.data_ast_desc, + # appr.data_ast_screen, + # appr.data_ast_scren_clas, + # appr.data_ast_cont, + # appr.data_ast_faq, + # appr.data_ast_estb_time, + # NOW() AS data_ast_upd_time, + # appr.data_ast_src, + # appr.ast_no, + # appr.data_ast_clas + # FROM t_data_ast_info_appr appr + # INNER JOIN ( + # SELECT + # ast_no, + # MAX(version_no) AS max_version + # FROM t_data_ast_info_appr + # WHERE approStatus = 'succeed' + # GROUP BY ast_no + # ) latest ON appr.ast_no = latest.ast_no AND appr.version_no = latest.max_version + # WHERE + # appr.data_ast_stat = '1' + # AND appr.changeType = 'add' + # AND appr.approStatus = 'succeed' + # ) source ON target.ast_no = source.ast_no + # SET + # target.data_ast_eng_name = source.data_ast_eng_name, + # target.data_ast_cn_name = source.data_ast_cn_name, + # target.data_ast_type = source.data_ast_type, + # target.data_ast_stat = source.data_ast_stat, + # target.data_ast_desc = source.data_ast_desc, + # target.data_ast_screen = source.data_ast_screen, + # target.data_ast_scren_clas = source.data_ast_scren_clas, + # target.data_ast_cont = source.data_ast_cont, + # target.data_ast_faq = source.data_ast_faq, + # target.data_ast_estb_time = source.data_ast_estb_time, + # target.data_ast_upd_time = source.data_ast_upd_time, + # target.data_ast_src = source.data_ast_src, + # target.data_ast_clas = source.data_ast_clas; + # """) + + # # 动态SQL:插入目标表中不存在的新记录 + # insert_sql = text(""" + # INSERT INTO t_data_ast_info ( + # data_ast_eng_name, + # data_ast_cn_name, + # data_ast_type, + # data_ast_stat, + # data_ast_desc, + # data_ast_screen, + # data_ast_scren_clas, + # data_ast_cont, + # data_ast_faq, + # data_ast_estb_time, + # data_ast_upd_time, + # data_ast_src, + # ast_no, + # data_ast_clas + # ) + # SELECT + # source.data_ast_eng_name, + # source.data_ast_cn_name, + # source.data_ast_type, + # source.data_ast_stat, + # source.data_ast_desc, + # source.data_ast_screen, + # source.data_ast_scren_clas, + # source.data_ast_cont, + # source.data_ast_faq, + # source.data_ast_estb_time, + # source.data_ast_upd_time, + # source.data_ast_src, + # source.ast_no, + # source.data_ast_clas + # FROM ( + # SELECT + # appr.data_ast_eng_name, + # appr.data_ast_cn_name, + # appr.data_ast_type, + # appr.data_ast_stat, + # appr.data_ast_desc, + # appr.data_ast_screen, + # appr.data_ast_scren_clas, + # appr.data_ast_cont, + # appr.data_ast_faq, + # appr.data_ast_estb_time, + # NOW() AS data_ast_upd_time, + # appr.data_ast_src, + # appr.ast_no, + # appr.data_ast_clas + # FROM t_data_ast_info_appr appr + # INNER JOIN ( + # SELECT + # ast_no, + # MAX(version_no) AS max_version + # FROM t_data_ast_info_appr + # WHERE approStatus = 'succeed' + # GROUP BY ast_no + # ) latest ON appr.ast_no = latest.ast_no AND appr.version_no = latest.max_version + # WHERE + # appr.data_ast_stat = '1' + # AND appr.changeType = 'add' + # AND appr.approStatus = 'succeed' + # ) source + # LEFT JOIN t_data_ast_info target ON source.ast_no = target.ast_no + # WHERE target.ast_no IS NULL; + # """) + + # # 执行更新SQL + # await db.execute(update_sql) + + # # 执行插入SQL + # await db.execute(insert_sql) + + # # 提交事务 + # await db.commit() - # 执行插入/更新语句 - await db.execute(upsert_stmt) - - # 提交会话使更改生效 - await db.commit() + # return "元数据成功发布到数据资产!" - return "元数据成功发布到数据资产!" + # except Exception as e: + # # 回滚事务 + # await db.rollback() + # raise e diff --git a/vue-fastapi-backend/module_admin/entity/do/dataast_do.py b/vue-fastapi-backend/module_admin/entity/do/dataast_do.py index 1b381a8..7081046 100644 --- a/vue-fastapi-backend/module_admin/entity/do/dataast_do.py +++ b/vue-fastapi-backend/module_admin/entity/do/dataast_do.py @@ -20,7 +20,7 @@ class DataAssetInfoAppr(Base): data_ast_upd_time = Column(DateTime, nullable=True, server_default=func.now(), onupdate=func.now(), comment='数据资产更新时间') data_ast_src = Column(String(255), nullable=True, comment='数据资产来源') ast_no = Column(Integer, nullable=True, comment='数据资产编号') - data_ast_clas = Column(String(255), nullable=True, comment='数据资产标签') + data_ast_clas = Column(String(3000), nullable=True, comment='数据资产标签') version_no = Column(String(50), nullable=True, comment='版本号') changeType = Column(String(10), default=None, comment='变更类型') flowId = Column(String(50), default=None, comment='审批Id') diff --git a/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py b/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py index 3a941fc..879ce8c 100644 --- a/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py +++ b/vue-fastapi-backend/module_admin/entity/vo/dataast_vo.py @@ -31,7 +31,8 @@ class DataAstInfoModel(BaseModel): data_ast_estb_time: Optional[datetime] = Field(default=None, description='数据资产建立时间', alias='dataAstEstbTime') data_ast_upd_time: Optional[datetime] = Field(default=None, description='数据资产更新时间', alias='dataAstUpdTime') data_ast_src: Optional[str] = Field(default=None, description='数据资产来源', alias='dataAstSrc') - ast_no: Optional[int] = Field(default=None, description='数据资产编号', alias='astNo') + #ast_no: Optional[int] = Field(default=None, description='数据资产编号', alias='astNo') + ast_no: int data_ast_clas: Optional[str] = Field(default=None, description='数据资产标签', alias='dataAstClas') version_no: Optional[str] = Field(default=None, description='版本号', alias='versionNo') create_by: Optional[str] = Field(default=None, description='创建人', alias='createBy') diff --git a/vue-fastapi-backend/module_admin/service/dataast_service.py b/vue-fastapi-backend/module_admin/service/dataast_service.py index e25088c..b0aed9d 100644 --- a/vue-fastapi-backend/module_admin/service/dataast_service.py +++ b/vue-fastapi-backend/module_admin/service/dataast_service.py @@ -66,5 +66,5 @@ class DataAstService: @classmethod - async def get_ast_main_appr_list(cls, query_db: AsyncSession, query_object: DataAstInfoModel, is_page: bool = False): - return await DataAstDao.get_ast_main_appr_list(query_object.flowId, query_db) \ No newline at end of file + async def get_ast_main_appr_list(cls, query_db: AsyncSession, flowId: str, is_page: bool = False): + return await DataAstDao.get_ast_main_appr_list(flowId, query_db) \ No newline at end of file diff --git a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue index 2a6d842..38f7e55 100644 --- a/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue +++ b/vue-fastapi-frontend/src/views/dataAsset/assetDetail/index.vue @@ -85,7 +85,18 @@ - + + + @@ -260,6 +271,39 @@ const getList = () => { loading.value = false; list.value = res.rows; total.value = res.total; + if (list.value.length>0){ + for (let i = 0; i < list.value.length; i++) { + let array = JSON.parse(list.value[i].dataAstClas) + if (array && array.length >0){ + let tempTabClas = [] + for (let j = 0; j < array.length; j++) { + if (tempTabClas.length > 0){ + let hasClas = false + for (let k = 0; k < tempTabClas.length; k++) { + if (tempTabClas[k].clasPriClas === array[j].clasPriClas + && tempTabClas[k].clasScdClas === array[j].clasScdClas + && tempTabClas[k].clasThreClas === array[j].clasThreClas){ + hasClas = true + } + } + if (hasClas){ + break + }else { + if (array[j].clasEffFlag === '1'){ + tempTabClas.push(array[j]) + } + } + }else { + if (array[j].clasEffFlag === '1') { + tempTabClas.push(array[j]) + } + } + } + list.value[i].showTabClas = array + list.value[i].tempTabClas = tempTabClas + } + } + } }); } const handleQuery = () => { diff --git a/vue-fastapi-frontend/src/views/meta/metaInfo/index.vue b/vue-fastapi-frontend/src/views/meta/metaInfo/index.vue index fbdca5b..820600d 100644 --- a/vue-fastapi-frontend/src/views/meta/metaInfo/index.vue +++ b/vue-fastapi-frontend/src/views/meta/metaInfo/index.vue @@ -583,10 +583,12 @@ + + @@ -595,22 +597,21 @@ - - - - - - - - - - - - - - - + + + + @@ -625,6 +626,90 @@ + + + + + + + + + + + + + + + + + + 新增 + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -709,6 +794,17 @@ const selectedRows = ref([]) const dataAstList= ref([]) const astPublish = ref(false) + const astTagDialog = ref(false) + const astTags = ref([]) + const currentAstTag = ref({ + "index":-1, + "clasThreClas": "", + "clasOnum": null, + "clasName": "", + "recSubmPrsn": "", + "clasPriClas": "", + "clasScdClas": "" + }); function changeColumnTab(){ if (activeColumnTab.value === 'businessRelation'){ @@ -762,6 +858,39 @@ currentMetaData.value.tags = JSON.parse(JSON.stringify(tableTags.value)) tableTagDialog.value = false } + function confirmAstTags(){ + dataAstList.value[currentAstTag.value.index].dataAstClas = JSON.parse(JSON.stringify(astTags.value)) + let tempTabClas = [] + if (astTags.value.length>0){ + for (let j = 0; j < astTags.value.length; j++) { + if (tempTabClas.length > 0){ + let hasClas = false + for (let k = 0; k < tempTabClas.length; k++) { + if (tempTabClas[k].clasPriClas === astTags.value[j].clasPriClas + && tempTabClas[k].clasScdClas === astTags.value[j].clasScdClas + && tempTabClas[k].clasThreClas === astTags.value[j].clasThreClas){ + hasClas = true + } + } + if (hasClas){ + break + }else { + if (astTags.value[j].clasEffFlag === '1'){ + tempTabClas.push(astTags.value[j]) + } + } + }else { + if (astTags.value[j].clasEffFlag === '1') { + tempTabClas.push(astTags.value[j]) + } + } + } + } + dataAstList.value[currentAstTag.value.index].showTabClas = astTags.value + dataAstList.value[currentAstTag.value.index].tempTabClas = tempTabClas + dataAstList.value[currentAstTag.value.index].dataAstClas = JSON.stringify(astTags.value) + astTagDialog.value = false + } function confirmColumn(){ let changed = false for (let i = 0; i < columnList.value.length; i++) { @@ -881,6 +1010,24 @@ proxy.$modal.msgWarning("请选择一个标签"); } + } + function addAstTag(){ + let json = JSON.parse(JSON.stringify(currentTableTag.value)) + if (json.clasOnum !== null){ + tableTags.value.push({ + onum: json.clasOnum, + clasName: json.clasName, + clasValue: '', + tagRemark:'', + clasEffFlag:'1', + tagSource:'手工', + setUser: cache.local.get("username"), + setTime: getNowDateTime() + }) + } else { + proxy.$modal.msgWarning("请选择一个标签"); + } + } function addColumnTag(){ let json = JSON.parse(JSON.stringify(currentColumnTag.value)) @@ -933,6 +1080,16 @@ } } } + function changeAstTag(){ + if (typeof currentAstTag.value.clasOnum !== null){ + for (let i = 0; i item.astNo === row.astNo); dataAstList.value.splice(index,1) } + function editAstTab(index,row) { + astTagDialog.value = true + astTags.value = JSON.parse(JSON.stringify(row.showTabClas)) + currentAstTag.value.index = index + } function applyDataAst(){ if(selectedRows.value.length === 0){ proxy.$modal.msgWarning("请至少选择一条元数据进行发布") @@ -1232,7 +1394,9 @@ dataAstDesc:'', dataAstSrc: row.ssysCd, astNo: row.extractOnum, - dataAstClas: JSON.stringify(row.batchTabClas) + // dataAstClas: JSON.stringify(row.batchTabClas) + showTabClas: row.showTabClas, + tempTabClas: row.tempTabClas }) }) diff --git a/vue-fastapi-frontend/src/views/system/flow/dataAssetMainAppr.vue b/vue-fastapi-frontend/src/views/system/flow/dataAssetMainAppr.vue index d92546f..5552287 100644 --- a/vue-fastapi-frontend/src/views/system/flow/dataAssetMainAppr.vue +++ b/vue-fastapi-frontend/src/views/system/flow/dataAssetMainAppr.vue @@ -13,9 +13,14 @@ @@ -96,6 +101,41 @@ const getList = async () => { const params = { flowId: props.flowId }; const res = await listAssetMainAppr(params); tableData.value = res.data || []; + + if (tableData.value.length>0){ + for (let i = 0; i < tableData.value.length; i++) { + let array = JSON.parse(tableData.value[i].dataAstClas) + if (array && array.length >0){ + let tempTabClas = [] + for (let j = 0; j < array.length; j++) { + if (tempTabClas.length > 0){ + let hasClas = false + for (let k = 0; k < tempTabClas.length; k++) { + if (tempTabClas[k].clasPriClas === array[j].clasPriClas + && tempTabClas[k].clasScdClas === array[j].clasScdClas + && tempTabClas[k].clasThreClas === array[j].clasThreClas){ + hasClas = true + } + } + if (hasClas){ + break + }else { + if (array[j].clasEffFlag === '1'){ + tempTabClas.push(array[j]) + } + } + }else { + if (array[j].clasEffFlag === '1') { + tempTabClas.push(array[j]) + } + } + } + tableData.value[i].showTabClas = array + tableData.value[i].tempTabClas = tempTabClas + } + } + } + } catch (e) { console.error('加载失败', e); } finally {