From d6366ddf931d83824cd14d34ce2fda437cb092a9 Mon Sep 17 00:00:00 2001 From: xueyinfei <1207092115@qq.com> Date: Mon, 17 Feb 2025 21:19:52 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=83=E6=95=B0=E6=8D=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vue-fastapi-backend/config/env.py | 2 +- .../controller/approval_controller.py | 57 ++ .../controller/meta_controller.py | 41 + .../module_admin/dao/approval_dao.py | 78 ++ .../module_admin/dao/meta_dao.py | 321 +++++++ .../module_admin/entity/do/aichat_do.py | 3 +- .../module_admin/entity/do/approval_do.py | 20 + .../module_admin/entity/do/meta_do.py | 156 +++ .../module_admin/entity/vo/approval_vo.py | 34 + .../module_admin/entity/vo/meta_vo.py | 56 ++ .../module_admin/service/approval_service.py | 121 +++ .../module_admin/service/meta_service.py | 126 +++ vue-fastapi-backend/server.py | 4 + vue-fastapi-frontend/package.json | 2 + vue-fastapi-frontend/src/api/aichat/aichat.js | 2 +- vue-fastapi-frontend/src/api/flow/flow.js | 25 + vue-fastapi-frontend/src/api/meta/metaInfo.js | 46 + .../src/components/TopNav/index.vue | 2 +- .../components/codemirror/SQLCodeMirror.vue | 72 ++ .../src/layout/components/Navbar.vue | 35 +- vue-fastapi-frontend/src/router/index.js | 14 + .../src/store/modules/user.js | 4 + vue-fastapi-frontend/src/utils/time.js | 1 + .../src/views/aichat/aichat.vue | 47 +- vue-fastapi-frontend/src/views/login.vue | 3 + .../src/views/meta/metaInfo/index.vue | 885 ++++++++++++++++++ .../src/views/system/flow/conf.vue | 11 + .../src/views/system/flow/index.vue | 140 +++ vue-fastapi-frontend/vite.config.js | 3 +- 29 files changed, 2275 insertions(+), 36 deletions(-) create mode 100644 vue-fastapi-backend/module_admin/controller/approval_controller.py create mode 100644 vue-fastapi-backend/module_admin/controller/meta_controller.py create mode 100644 vue-fastapi-backend/module_admin/dao/approval_dao.py create mode 100644 vue-fastapi-backend/module_admin/dao/meta_dao.py create mode 100644 vue-fastapi-backend/module_admin/entity/do/approval_do.py create mode 100644 vue-fastapi-backend/module_admin/entity/do/meta_do.py create mode 100644 vue-fastapi-backend/module_admin/entity/vo/approval_vo.py create mode 100644 vue-fastapi-backend/module_admin/entity/vo/meta_vo.py create mode 100644 vue-fastapi-backend/module_admin/service/approval_service.py create mode 100644 vue-fastapi-backend/module_admin/service/meta_service.py create mode 100644 vue-fastapi-frontend/src/api/flow/flow.js create mode 100644 vue-fastapi-frontend/src/api/meta/metaInfo.js create mode 100644 vue-fastapi-frontend/src/components/codemirror/SQLCodeMirror.vue create mode 100644 vue-fastapi-frontend/src/views/meta/metaInfo/index.vue create mode 100644 vue-fastapi-frontend/src/views/system/flow/conf.vue create mode 100644 vue-fastapi-frontend/src/views/system/flow/index.vue diff --git a/vue-fastapi-backend/config/env.py b/vue-fastapi-backend/config/env.py index 6af5783..1401c1b 100644 --- a/vue-fastapi-backend/config/env.py +++ b/vue-fastapi-backend/config/env.py @@ -14,7 +14,7 @@ class AppSettings(BaseSettings): app_env: str = 'dev' app_name: str = 'RuoYi-FasAPI' - app_root_path: str = '/dev-api' + app_root_path: str = '/default-api' app_host: str = '0.0.0.0' app_port: int = 9099 app_version: str = '1.0.0' diff --git a/vue-fastapi-backend/module_admin/controller/approval_controller.py b/vue-fastapi-backend/module_admin/controller/approval_controller.py new file mode 100644 index 0000000..cc22957 --- /dev/null +++ b/vue-fastapi-backend/module_admin/controller/approval_controller.py @@ -0,0 +1,57 @@ +import json +import os +import shutil +from fastapi import APIRouter, Depends, Request, UploadFile, File, Form +from sqlalchemy.ext.asyncio import AsyncSession +from config.get_db import get_db +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject +from module_admin.service.login_service import LoginService +from module_admin.service.approval_service import ApprovalService +from utils.log_util import logger +from utils.response_util import ResponseUtil + +approvalController = APIRouter(prefix='/approval', dependencies=[Depends(LoginService.get_current_user)]) + + +@approvalController.post("/apply") +async def flow_apply(request: Request, + apply: ApplyModel, + query_db: AsyncSession = Depends(get_db)): + apply_result = await ApprovalService.apply_services(query_db, apply) + return ResponseUtil.success(msg=apply_result.message) + + +@approvalController.post("/operate") +async def flow_operate(request: Request, + operate: OperateModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + operate_result = await ApprovalService.operate_services(query_db, operate, current_user) + return ResponseUtil.success(msg=operate_result.message) + + +@approvalController.get("/list") +async def flow_list(request: Request, + query_param: ApprovalQueryObject = Depends(ApprovalQueryObject.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + meta_query_result = await ApprovalService.get_flow_list_services(query_db, query_param, current_user) + return ResponseUtil.success(data=meta_query_result) + + +@approvalController.get("/waitingTotal") +async def getWaitingTotal(request: Request, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + meta_query_result = await ApprovalService.get_waiting_total_services(query_db, current_user) + return ResponseUtil.success(data=meta_query_result) + + +@approvalController.post("/cancelApply/{flow_id}") +async def cancel_apply(request: Request, + flow_id: str, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + operate_result = await ApprovalService.cancel_apply_services(query_db, flow_id, current_user) + return ResponseUtil.success(msg=operate_result.message) diff --git a/vue-fastapi-backend/module_admin/controller/meta_controller.py b/vue-fastapi-backend/module_admin/controller/meta_controller.py new file mode 100644 index 0000000..8a7de27 --- /dev/null +++ b/vue-fastapi-backend/module_admin/controller/meta_controller.py @@ -0,0 +1,41 @@ +from fastapi import APIRouter, Depends, Request +from sqlalchemy.ext.asyncio import AsyncSession +from config.get_db import get_db +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.service.login_service import LoginService +from utils.response_util import ResponseUtil + +from module_admin.service.meta_service import MetaService +from module_admin.entity.vo.meta_vo import MetaPageObject, MetaColObject, SuppleModel + +metaController = APIRouter(prefix='/dasset', dependencies=[Depends(LoginService.get_current_user)]) + + +@metaController.get("/meta/get") +async def get_meta_list(request: Request, meta_query: MetaPageObject = Depends(MetaPageObject.as_query), + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + meta_query_result = await MetaService.get_meta_list_services(query_db, meta_query, current_user) + return ResponseUtil.success(data=meta_query_result) + + +@metaController.get("/meta/column/list") +async def get_meta_list(request: Request, meta_query: MetaColObject = Depends(MetaColObject.as_query), + query_db: AsyncSession = Depends(get_db)): + meta_query_result = await MetaService.get_meta_col_list_services(query_db, meta_query) + return ResponseUtil.success(data=meta_query_result) + + +@metaController.get("/meta/clas/list") +async def get_meta_clas_list(request: Request, query_db: AsyncSession = Depends(get_db)): + result = await MetaService.get_meta_clas_list_services(query_db) + return ResponseUtil.success(data=result) + + +@metaController.post("/meta/supp") +async def meta_supp(request: Request, + supple: SuppleModel, + query_db: AsyncSession = Depends(get_db), + current_user: CurrentUserModel = Depends(LoginService.get_current_user)): + result = await MetaService.meta_supp(query_db, supple, current_user) + return ResponseUtil.success(msg=result.message) diff --git a/vue-fastapi-backend/module_admin/dao/approval_dao.py b/vue-fastapi-backend/module_admin/dao/approval_dao.py new file mode 100644 index 0000000..b74cd70 --- /dev/null +++ b/vue-fastapi-backend/module_admin/dao/approval_dao.py @@ -0,0 +1,78 @@ +from sqlalchemy import desc, delete, func, select, update +from sqlalchemy.ext.asyncio import AsyncSession +from module_admin.entity.do.approval_do import FlowApproval +from module_admin.entity.vo.approval_vo import ApprovalQueryObject +from module_admin.entity.vo.user_vo import CurrentUserModel +from sqlalchemy import select, text, cast, Integer, and_, or_, outerjoin, func, join +from utils.page_util import PageUtil + + +class ApprovalDao: + """ + 菜单管理模块数据库操作层 + """ + + @classmethod + async def add_flow_approval(cls, db: AsyncSession, flow_approval: FlowApproval): + db.add(flow_approval) + await db.flush() + return flow_approval + + @classmethod + async def get_flow_by_id(cls, db: AsyncSession, flowId: str): + result = ( + ( + await db.execute( + select(FlowApproval).where( + FlowApproval.id == flowId + ) + ) + ) + .scalars() + .first() + ) + return result + + @classmethod + async def edit_flow_approval(cls, db: AsyncSession, flow: dict): + await db.execute(update(FlowApproval), [flow]) + + @classmethod + async def get_flow_list(cls, db: AsyncSession, query_param: ApprovalQueryObject, current_user: CurrentUserModel): + query = ( + select(FlowApproval) + .where( + (FlowApproval.applicant == query_param.status) if query_param.applicant else True, + (FlowApproval.businessType == query_param.businessType) if query_param.businessType else True, + or_( + FlowApproval.approver == current_user.user.user_name, + FlowApproval.approver.in_(current_user.roles) + ) if current_user.user.user_name != 'admin' else True + ) + .order_by(FlowApproval.applyTime) + .distinct() + ) + # 注意:这里不执行查询,而是将查询对象传递给 paginate 方法 + result = await PageUtil.paginate(db, query, query_param.page_num, query_param.page_size, True) + return result + + @classmethod + async def get_waiting_total(cls, db: AsyncSession, current_user: CurrentUserModel): + return (await db.execute(select(func.count()).select_from(FlowApproval) + .where(FlowApproval.approver == current_user.user.user_name))).scalar() + + @classmethod + async def get_flow_by_idAndUser(cls, db: AsyncSession, flow_id: str, username: str): + result = ( + ( + await db.execute( + select(FlowApproval).where( + FlowApproval.id == flow_id, + FlowApproval.applicant == username + ) + ) + ) + .scalars() + .first() + ) + return result diff --git a/vue-fastapi-backend/module_admin/dao/meta_dao.py b/vue-fastapi-backend/module_admin/dao/meta_dao.py new file mode 100644 index 0000000..4502705 --- /dev/null +++ b/vue-fastapi-backend/module_admin/dao/meta_dao.py @@ -0,0 +1,321 @@ +from sqlalchemy.ext.asyncio import AsyncSession +from sqlalchemy import select, text, cast, Integer, and_, or_, outerjoin, func, join, update, desc +from module_admin.entity.vo.meta_vo import MetaPageObject, MetaColObject +from module_admin.entity.do.meta_do import MetadataExtractInfo, MetadataSuppInfo, MetadataFldTabExtractInfo, \ + MetadataFldSuppInfo, MetadataClas, MetadataSuppInfoVett, MetadataFldSuppInfoVett +import json +import re +from utils.time_format_util import object_format_datetime, list_format_datetime, format_datetime_dict_list +from datetime import datetime, time +from typing import Union, List +from utils.log_util import logger +import uuid +import datetime +from utils.page_util import PageUtil + + +class MetaDao: + + @classmethod + async def get_meta_rel_list(cls, db: AsyncSession, query_object: MetaPageObject): + """ + 根据查询参数获取用户列表信息 + """ + # 主查询 + query = ( + select( + MetadataExtractInfo.onum.label('extract_onum'), + MetadataExtractInfo.extract_ver_num, + MetadataExtractInfo.ver_desc.label('extract_ver_desc'), + MetadataExtractInfo.ssys_cd, + MetadataExtractInfo.data_whs_name, + MetadataExtractInfo.mdl_name, + MetadataExtractInfo.tab_no, + MetadataExtractInfo.tab_type, + MetadataExtractInfo.tab_eng_name, + MetadataExtractInfo.tab_cn_name, + MetadataExtractInfo.tab_rec_num, + MetadataExtractInfo.upd_time.label('extract_upd_time'), + MetadataSuppInfo.onum.label('supp_onum'), + MetadataSuppInfo.crrct_ver_num.label('supp_crrct_ver_num'), + MetadataSuppInfo.tab_crrct_name, + MetadataSuppInfo.tab_desc, + MetadataSuppInfo.pic, + MetadataSuppInfo.gov_flag, + MetadataSuppInfo.rec_stat.label('supp_rec_stat'), + MetadataSuppInfo.tab_clas, + MetadataSuppInfo.rec_subm_prsn, + MetadataSuppInfo.upd_time.label('supp_upd_time') + ).join(MetadataSuppInfo, + and_( + MetadataExtractInfo.ssys_cd == MetadataSuppInfo.ssys_cd, + MetadataExtractInfo.mdl_name == MetadataSuppInfo.mdl_name, + MetadataExtractInfo.tab_eng_name == MetadataSuppInfo.tab_eng_name + ), isouter=True) + .join( + MetadataFldTabExtractInfo, + and_( + MetadataExtractInfo.ssys_cd == MetadataFldTabExtractInfo.ssys_cd, + MetadataExtractInfo.mdl_name == MetadataFldTabExtractInfo.mdl_name, + MetadataExtractInfo.tab_eng_name == MetadataFldTabExtractInfo.tab_eng_name + ), isouter=True) + .join( + MetadataFldSuppInfo, + and_( + MetadataExtractInfo.ssys_cd == MetadataFldSuppInfo.ssys_cd, + MetadataExtractInfo.mdl_name == MetadataFldSuppInfo.mdl_name, + MetadataExtractInfo.tab_eng_name == MetadataFldSuppInfo.tab_eng_name + ), isouter=True) + .where( + MetadataExtractInfo.ssys_cd == query_object.ssys_cd if query_object.ssys_cd else True, + MetadataExtractInfo.mdl_name == query_object.mdl_name if query_object.mdl_name else True, + or_(MetadataExtractInfo.tab_eng_name.like(f'%{query_object.tab_name}%'), + MetadataExtractInfo.tab_cn_name.like(f'%{query_object.tab_name}%'), + MetadataSuppInfo.tab_eng_name.like(f'%{query_object.tab_name}%'), + MetadataSuppInfo.tab_crrct_name.like(f'%{query_object.tab_name}%'), + ) if query_object.tab_name else True, + or_( + MetadataFldTabExtractInfo.fld_eng_name.like(f'%{query_object.col_name}%'), + MetadataFldTabExtractInfo.fld_cn_name.like(f'%{query_object.col_name}%'), + MetadataFldSuppInfo.fld_eng_name.like(f'%{query_object.col_name}%'), + MetadataFldSuppInfo.fld_crrct_name.like(f'%{query_object.col_name}%'), + ) if query_object.col_name else True, + MetadataExtractInfo.tab_type == query_object.tab_type if query_object.tab_type else True, + MetadataExtractInfo.rec_stat == query_object.rec_stat if query_object.rec_stat else True, + ).distinct() + ) + result = await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, True) + return result + + @classmethod + async def get_meta_col_list(cls, db: AsyncSession, query_object: MetaColObject): + query_result = ( + ( + await db.execute( + select( + MetadataFldTabExtractInfo.onum.label('extract_onum'), + MetadataFldTabExtractInfo.extract_ver_num, + MetadataFldTabExtractInfo.ssys_cd, + MetadataFldTabExtractInfo.data_whs_name, + MetadataFldTabExtractInfo.mdl_name, + MetadataFldTabExtractInfo.tab_no, + MetadataFldTabExtractInfo.tab_eng_name, + MetadataFldTabExtractInfo.fld_no, + MetadataFldTabExtractInfo.fld_eng_name, + MetadataFldTabExtractInfo.fld_cn_name, + MetadataFldTabExtractInfo.fld_type, + MetadataFldTabExtractInfo.pk_flag, + MetadataFldTabExtractInfo.require_flag, + MetadataFldTabExtractInfo.idx_flag, + MetadataFldTabExtractInfo.upd_time.label('extract_upd_time'), + MetadataFldSuppInfo.onum.label('supp_onum'), + MetadataFldSuppInfo.crrct_ver_num, + MetadataFldSuppInfo.fld_crrct_name, + MetadataFldSuppInfo.crrct_pk_flag, + MetadataFldSuppInfo.fld_desc, + MetadataFldSuppInfo.pic, + MetadataFldSuppInfo.fld_clas, + MetadataFldSuppInfo.fld_null_rate, + MetadataFldSuppInfo.rec_stat.label('supp_rec_stat'), + MetadataFldSuppInfo.upd_time.label('supp_upd_time') + ).select_from( + join( + MetadataFldTabExtractInfo, + MetadataFldSuppInfo, + and_( + MetadataFldTabExtractInfo.ssys_cd == MetadataFldSuppInfo.ssys_cd, + MetadataFldTabExtractInfo.mdl_name == MetadataFldSuppInfo.mdl_name, + MetadataFldTabExtractInfo.tab_eng_name == MetadataFldSuppInfo.tab_eng_name, + MetadataFldTabExtractInfo.fld_eng_name == MetadataFldSuppInfo.fld_eng_name + ), isouter=True + ) + ).where( + MetadataFldTabExtractInfo.ssys_cd == query_object.ssys_cd, + MetadataFldTabExtractInfo.mdl_name == query_object.mdl_name, + MetadataFldTabExtractInfo.tab_eng_name == query_object.tab_name + ).distinct() + ) + ).all() + ) + return [row._asdict() for row in query_result] + + @classmethod + async def get_meta_clas_list(cls, db: AsyncSession): + query_result = ( + ( + await db.execute( + select(MetadataClas).where(MetadataClas.clas_eff_flag == 1).distinct() + ) + ).scalars().all() + ) + return query_result + + @classmethod + async def get_lastest_meta_data_supp_vett(cls, db: AsyncSession, ssys_cd: str, mdl_name: str, tab_eng_name: str): + query_result = ( + ( + await db.execute( + select(MetadataSuppInfoVett).where(MetadataSuppInfoVett.ssys_cd == ssys_cd, + MetadataSuppInfoVett.mdl_name == mdl_name, + MetadataSuppInfoVett.tab_eng_name == tab_eng_name) + .order_by(desc(MetadataSuppInfoVett.apply_time)) + .distinct().limit(1) + ) + ).scalars().first() + ) + return query_result + + @classmethod + async def insertMetadataSuppInfoVett(cls, table: MetadataSuppInfoVett, db: AsyncSession): + db.add(table) + await db.flush() + return table + + @classmethod + async def updateMetadataSuppInfoVett(cls, onum: str, operateType: str, db: AsyncSession): + table = dict( + onum=onum, + apply_status=operateType + ) + await db.execute(update(MetadataSuppInfoVett), [table]) + + @classmethod + async def insertMetadataSuppInfo(cls, table: MetadataSuppInfoVett, db: AsyncSession): + suppTable = MetadataSuppInfo() + suppTable.onum = uuid.uuid4() + suppTable.ssys_cd = table.ssys_cd + suppTable.mdl_name = table.mdl_name + suppTable.tab_eng_name = table.tab_eng_name + suppTable.tab_crrct_name = table.tab_crrct_name + suppTable.tab_desc = table.tab_desc + suppTable.pic = table.pic + suppTable.gov_flag = table.gov_flag + suppTable.rec_stat = table.rec_stat + suppTable.tab_clas = table.tab_clas + suppTable.rec_subm_prsn = table.rec_subm_prsn + suppTable.upd_time = table.upd_time + db.add(suppTable) + await db.flush() + return suppTable + + @classmethod + async def updateMetadataSuppInfo(cls, onum: str, table: MetadataSuppInfoVett, db: AsyncSession): + suppTable = dict( + onum=onum, + tab_crrct_name=table.tab_crrct_name, + tab_desc=table.tab_desc, + pic=table.pic, + gov_flag=table.gov_flag, + rec_stat=table.rec_stat, + tab_clas=table.tab_clas, + rec_subm_prsn=table.rec_subm_prsn, + upd_time=table.upd_time + ) + await db.execute(update(MetadataSuppInfo), [suppTable]) + + @classmethod + async def get_supp_table_vett_by_id(cls, suppId: str, db: AsyncSession): + query_result = ( + ( + await db.execute( + select(MetadataSuppInfoVett).where(MetadataSuppInfoVett.onum == suppId).distinct() + ) + ).scalars().first() + ) + return query_result + + @classmethod + async def get_supp_table_by_vett(cls, sysCode: str, mdlName: str, tableName: str, db: AsyncSession): + query_result = ( + ( + await db.execute( + select(MetadataSuppInfo).where(MetadataSuppInfo.ssys_cd == sysCode, + MetadataSuppInfo.mdl_name == mdlName, + MetadataSuppInfo.tab_eng_name == tableName).distinct() + ) + ).scalars().first() + ) + return query_result + + @classmethod + async def insertMetadataFldSuppInfoVett(cls, column: MetadataFldSuppInfoVett, db: AsyncSession): + db.add(column) + await db.flush() + return column + + @classmethod + async def updateMetadataFldSuppInfoVett(cls, onum: str, operateType: str, db: AsyncSession): + updateColumn = dict( + onum=onum, apply_status=operateType + ) + await db.execute(update(MetadataFldSuppInfoVett), [updateColumn]) + + @classmethod + async def updateMetadataFldSuppInfo(cls, onum: str, column: MetadataFldSuppInfoVett, db: AsyncSession): + updateColumn = dict( + onum=onum, + fld_crrct_name=column.fld_crrct_name, + crrct_pk_flag=column.crrct_pk_flag, + fld_desc=column.fld_desc, + pic=column.pic, + fld_clas=column.fld_clas, + fld_null_rate=column.fld_null_rate, + rec_stat=column.rec_stat, + upd_time=column.upd_time, + ) + await db.execute(update(MetadataFldSuppInfo), [updateColumn]) + + @classmethod + async def insertMetadataFldSuppInfo(cls, column: MetadataFldSuppInfoVett, db: AsyncSession): + suppColumn = MetadataFldSuppInfo() + suppColumn.onum = uuid.uuid4() + suppColumn.ssys_cd = column.ssys_cd + suppColumn.mdl_name = column.mdl_name + suppColumn.tab_eng_name = column.tab_eng_name + suppColumn.fld_eng_name = column.fld_eng_name + suppColumn.fld_crrct_name = column.fld_crrct_name + suppColumn.crrct_pk_flag = column.crrct_pk_flag + suppColumn.fld_desc = column.fld_desc + suppColumn.pic = column.pic + suppColumn.fld_clas = column.fld_clas + suppColumn.fld_null_rate = column.fld_null_rate + suppColumn.rec_stat = column.rec_stat + suppColumn.upd_time = column.upd_time + db.add(suppColumn) + await db.flush() + return suppColumn + + @classmethod + async def get_meta_col_supp_vett(cls, table: MetadataSuppInfoVett, db: AsyncSession): + sql_query = text("select max(apply_time) from t_metadata_fld_supp_info_vett where ssys_cd ='" + table.ssys_cd + + "' and mdl_name = '" + table.mdl_name + "' and tab_eng_name = '" + table.tab_eng_name + + "'") + maxTime = (await db.execute(sql_query)).scalar() + + query_result = ( + ( + await db.execute( + select(MetadataFldSuppInfoVett) + .where(MetadataFldSuppInfoVett.ssys_cd == table.ssys_cd, + MetadataFldSuppInfoVett.mdl_name == table.mdl_name, + MetadataFldSuppInfoVett.tab_eng_name == table.tab_eng_name, + MetadataFldSuppInfoVett.apply_time == maxTime).distinct() + ) + ).scalars().all() + ) + return query_result + + @classmethod + async def get_supp_column_by_vett(cls, column: MetadataFldSuppInfoVett, db: AsyncSession): + query_result = ( + ( + await db.execute( + select(MetadataFldSuppInfo) + .where(MetadataFldSuppInfo.ssys_cd == column.ssys_cd, + MetadataFldSuppInfo.mdl_name == column.mdl_name, + MetadataFldSuppInfo.tab_eng_name == column.tab_eng_name, + MetadataFldSuppInfo.fld_eng_name == column.fld_eng_name).distinct() + ) + ).scalars().first() + ) + return query_result diff --git a/vue-fastapi-backend/module_admin/entity/do/aichat_do.py b/vue-fastapi-backend/module_admin/entity/do/aichat_do.py index fc85b07..0a9e50d 100644 --- a/vue-fastapi-backend/module_admin/entity/do/aichat_do.py +++ b/vue-fastapi-backend/module_admin/entity/do/aichat_do.py @@ -1,6 +1,7 @@ from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text from config.database import Base from datetime import datetime +from sqlalchemy.dialects.mysql import LONGTEXT class AiChatHistory(Base): @@ -17,7 +18,7 @@ class AiChatHistory(Base): isStop = Column(Boolean, default=None, comment='是否停止') user = Column(Integer, default=None, comment='所属用户') time = Column(String(50), default=None, comment='问答时间') - content = Column(Text, default=None, comment='问答内容') + content = Column(LONGTEXT, default=None, comment='问答内容') operate = Column(String(50), default=None, comment='点赞,差评等操作') thumbDownReason = Column(String(255), default=None, comment='差评原因') file = Column(String(255), default=None, comment='文件id集合') diff --git a/vue-fastapi-backend/module_admin/entity/do/approval_do.py b/vue-fastapi-backend/module_admin/entity/do/approval_do.py new file mode 100644 index 0000000..c9a273b --- /dev/null +++ b/vue-fastapi-backend/module_admin/entity/do/approval_do.py @@ -0,0 +1,20 @@ +from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text +from config.database import Base +from datetime import datetime + + +class FlowApproval(Base): + """ + 流程审批表 + """ + __tablename__ = 'flow_approval' + + id = Column(String(50), primary_key=True, comment='id') + businessType = Column(String(50), default='', comment='业务审批模块') + businessId = Column(String(255), default='', comment='业务id串') + applicant = Column(String(50), default=None, comment='申请人') + applyTime = Column(String(50), default=None, comment='审批时间') + approver = Column(String(50), default=None, comment='下一步审批人') + nextStep = Column(Integer, default=None, comment="下一步编号") + status = Column(String(10), default=None, comment='状态') + approvalFlow = Column(Text, default=None, comment='审批流') # [{审批人:‘’,审批时间:‘’,'审批结果':‘’,审批意见:''},{}]数组 diff --git a/vue-fastapi-backend/module_admin/entity/do/meta_do.py b/vue-fastapi-backend/module_admin/entity/do/meta_do.py new file mode 100644 index 0000000..703fbb2 --- /dev/null +++ b/vue-fastapi-backend/module_admin/entity/do/meta_do.py @@ -0,0 +1,156 @@ +from sqlalchemy import Column, Float, Integer, String, Text, DateTime, Boolean, ForeignKey, UniqueConstraint, Index, \ + text +from config.database import Base +from datetime import datetime + + +class MetadataExtractInfo(Base): + """ + 元数据采集信息表 + """ + __tablename__ = 't_metadata_extract_info' + + onum = Column(Integer, primary_key=True, comment='唯一编号') + extract_ver_num = Column(String(50, collation='utf8_general_ci'), comment='采集版本号') + ver_desc = Column(String(250, collation='utf8_general_ci'), comment='版本描述') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + data_whs_name = Column(String(50, collation='utf8_general_ci'), comment='数据仓库名称') + mdl_name = Column(String(50, collation='utf8_general_ci'), comment='模式名称') + tab_no = Column(Integer, comment='表编号') + tab_type = Column(String(50, collation='utf8_general_ci'), comment='表类型') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + tab_cn_name = Column(String(250, collation='utf8_general_ci'), comment='表中文名称') + tab_rec_num = Column(Integer, comment='记录数') + upd_time = Column(DateTime, comment='更新时间') + + +class MetadataSuppInfo(Base): + """ + 元数据补充信息表 + """ + __tablename__ = 't_metadata_supp_info' + + # onum = Column(Integer, primary_key=True, comment='唯一编号') + onum = Column(String(36, collation='utf8mb4_unicode_ci'), primary_key=True, comment='唯一编号') + crrct_ver_num = Column(String(50, collation='utf8_general_ci'), comment='补录版本号') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + mdl_name = Column(String(50, collation='utf8_general_ci'), comment='模型名称') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + tab_crrct_name = Column(String(250, collation='utf8_general_ci'), comment='表补录名称') + tab_desc = Column(String(500, collation='utf8_general_ci'), comment='表描述') + pic = Column(String(64, collation='utf8_general_ci'), comment='表图片') + gov_flag = Column(String(1, collation='utf8_general_ci'), default='0', comment='治理标志(0否 1是)') + rec_stat = Column(String(1, collation='utf8_general_ci'), default='0', comment='记录状态(0有效 1无效)') + tab_clas = Column(Text, comment='表分类') + rec_subm_prsn = Column(String(255, collation='utf8_general_ci'), comment='记录提交人') + upd_time = Column(DateTime, comment='更新时间') + + +class MetadataSuppInfoVett(Base): + """ + 元数据补充信息审批表 + """ + __tablename__ = 't_metadata_supp_info_vett' + + # onum = Column(Integer, primary_key=True, comment='唯一编号') + onum = Column(String(36, collation='utf8mb4_unicode_ci'), primary_key=True, comment='唯一编号') + crrct_ver_num = Column(String(50, collation='utf8_general_ci'), comment='补录版本号') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + mdl_name = Column(String(50, collation='utf8_general_ci'), comment='模型名称') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + tab_crrct_name = Column(String(250, collation='utf8_general_ci'), comment='表补录名称') + tab_desc = Column(String(500, collation='utf8_general_ci'), comment='表描述') + pic = Column(String(64, collation='utf8_general_ci'), comment='表图片') + gov_flag = Column(String(1, collation='utf8_general_ci'), default='0', comment='治理标志(0否 1是)') + rec_stat = Column(String(1, collation='utf8_general_ci'), default='0', comment='记录状态(0有效 1无效)') + tab_clas = Column(Text, comment='表分类') + rec_subm_prsn = Column(String(255, collation='utf8_general_ci'), comment='记录提交人') + apply_time = Column(String(255, collation='utf8_general_ci'), comment='申请时间') + apply_status = Column(String(255, collation='utf8_general_ci'), comment='申请状态') + upd_time = Column(String(255, collation='utf8_general_ci'), comment='更新时间') + + +class MetadataClas(Base): + """ + 元数据分类表 + """ + __tablename__ = 't_metadata_clas' + + clas_onum = Column(Integer, primary_key=True, comment='分类编号') + clas_pri_clas = Column(String(50, collation='utf8_general_ci'), comment='一级分类') + clas_scd_clas = Column(String(50, collation='utf8_general_ci'), comment='二级分类') + clas_thre_clas = Column(String(50, collation='utf8_general_ci'), comment='三级分类') + clas_name = Column(String(255, collation='utf8_general_ci'), comment='分类名称') + clas_eff_flag = Column(String(1, collation='utf8_general_ci'), default='0', comment='生效标志(0有效 1无效)') + rec_subm_prsn = Column(String(255, collation='utf8_general_ci'), comment='记录提交人') + upd_time = Column(DateTime, comment='更新时间') + + +class MetadataFldTabExtractInfo(Base): + """ + 字段采集信息表 + """ + __tablename__ = 't_metadata_fld_tab_extract_info' + + onum = Column(Integer, primary_key=True, comment='唯一编号') + extract_ver_num = Column(String(50, collation='utf8_general_ci'), comment='采集版本号') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + data_whs_name = Column(String(255, collation='utf8_general_ci'), comment='数据仓库名称') + mdl_name = Column(String(255, collation='utf8_general_ci'), comment='模块名称') + tab_no = Column(String(50, collation='utf8_general_ci'), comment='表编号') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + fld_no = Column(Integer, comment='字段编号') + fld_eng_name = Column(String(255, collation='utf8_general_ci'), comment='字段英文名称') + fld_cn_name = Column(String(255, collation='utf8_general_ci'), comment='字段中文名称') + fld_type = Column(String(50, collation='utf8_general_ci'), comment='字段类型') + pk_flag = Column(Boolean, default=False, comment='是否为主键') #待确认字段类型 + require_flag = Column(Boolean, default=False, comment='是否必填') + idx_flag = Column(Boolean, default=False, comment='是否为索引') + upd_time = Column(DateTime, comment='更新时间') + + +class MetadataFldSuppInfo(Base): + """ + 字段补充信息表 + """ + __tablename__ = 't_metadata_fld_supp_info' + + onum = Column(String(50, collation='utf8_general_ci'), primary_key=True, comment='唯一编号') + crrct_ver_num = Column(String(50, collation='utf8_general_ci'), comment='补充版本号') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + mdl_name = Column(String(255, collation='utf8_general_ci'), comment='模块名称') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + fld_eng_name = Column(String(255, collation='utf8_general_ci'), comment='字段英文名称') + fld_crrct_name = Column(String(255, collation='utf8_general_ci'), comment='补充字段名称') + crrct_pk_flag = Column(Boolean, default=False, comment='是否为主键') + fld_desc = Column(String(255, collation='utf8_general_ci'), comment='字段描述') + pic = Column(String(255, collation='utf8_general_ci'), comment='图片字段') + fld_clas = Column(Text, comment='字段分类') + fld_null_rate = Column(String(50, collation='utf8_general_ci'), comment='字段空值率') + rec_stat = Column(String(50, collation='utf8_general_ci'), comment='记录状态') + upd_time = Column(DateTime, comment='更新时间') + + +class MetadataFldSuppInfoVett(Base): + """ + 字段补充信息表 + """ + __tablename__ = 't_metadata_fld_supp_info_vett' + + onum = Column(String(50, collation='utf8_general_ci'), primary_key=True, comment='唯一编号') + crrct_ver_num = Column(String(50, collation='utf8_general_ci'), comment='补充版本号') + ssys_cd = Column(String(50, collation='utf8_general_ci'), comment='系统代码') + mdl_name = Column(String(255, collation='utf8_general_ci'), comment='模块名称') + tab_eng_name = Column(String(250, collation='utf8_general_ci'), comment='表英文名称') + fld_eng_name = Column(String(255, collation='utf8_general_ci'), comment='字段英文名称') + fld_crrct_name = Column(String(255, collation='utf8_general_ci'), comment='补充字段名称') + crrct_pk_flag = Column(Boolean, default=False, comment='是否为主键') + fld_desc = Column(String(255, collation='utf8_general_ci'), comment='字段描述') + pic = Column(String(255, collation='utf8_general_ci'), comment='图片字段') + fld_clas = Column(Text, comment='字段分类') + fld_null_rate = Column(String(50, collation='utf8_general_ci'), comment='字段空值率') + rec_stat = Column(String(50, collation='utf8_general_ci'), comment='记录状态') + upd_time = Column(DateTime, comment='更新时间') + rec_subm_prsn = Column(String(255, collation='utf8_general_ci'), comment='记录提交人') + apply_time = Column(String(255, collation='utf8_general_ci'), comment='申请时间') + apply_status = Column(String(255, collation='utf8_general_ci'), comment='申请状态') diff --git a/vue-fastapi-backend/module_admin/entity/vo/approval_vo.py b/vue-fastapi-backend/module_admin/entity/vo/approval_vo.py new file mode 100644 index 0000000..1fcce05 --- /dev/null +++ b/vue-fastapi-backend/module_admin/entity/vo/approval_vo.py @@ -0,0 +1,34 @@ +from pydantic import BaseModel +from typing import Union, Optional, List +from module_admin.annotation.pydantic_annotation import as_query +from pydantic import BaseModel, ConfigDict, Field, model_validator +from pydantic.alias_generators import to_camel + + +class ApplyModel(BaseModel): + businessType: Optional[str] = None + businessId: Optional[str] = None + applicant: Optional[str] = None + + +class OperateModel(BaseModel): + flowId: Optional[str] = None # 流程编号 + operateType: Optional[str] = None # 操作:驳回,同意:reject, success + operateComment: Optional[str] = None # 审批意见 + + +@as_query +class ApprovalQueryObject(BaseModel): + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) + page_num: int + page_size: int + applicant: Optional[str] = None + businessType: Optional[str] = None + + +class EditObjectModel(BaseModel): + id: Optional[str] = None + status: Optional[str] = None + approver: Optional[str] = None + nextStep: Optional[int] = None + approvalFlow: Optional[str] = None diff --git a/vue-fastapi-backend/module_admin/entity/vo/meta_vo.py b/vue-fastapi-backend/module_admin/entity/vo/meta_vo.py new file mode 100644 index 0000000..88dfa5a --- /dev/null +++ b/vue-fastapi-backend/module_admin/entity/vo/meta_vo.py @@ -0,0 +1,56 @@ +from typing import Union, Optional, List +from datetime import datetime +from module_admin.annotation.pydantic_annotation import as_query +from pydantic import BaseModel, ConfigDict, Field, model_validator +from pydantic.alias_generators import to_camel + + +class MetaModel(BaseModel): + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) + ssys_cd: Optional[str] = Field(default=None, description='系统名称') + mdl_name: Optional[str] = Field(default=None, description='模式名称') + tab_name: Optional[str] = Field(default=None, description='表名') + tab_type: Optional[str] = Field(default=None, description='表类型') + col_name: Optional[str] = Field(default=None, description='字段名称') + tag_name: Optional[str] = Field(default=None, description='标签名称') + rec_stat: Optional[str] = Field(default=None, description='补录状态') + + +@as_query +class MetaPageObject(MetaModel): + page_num: int + page_size: int + + +@as_query +class MetaColObject(BaseModel): + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) + ssys_cd: Optional[str] = Field(default=None, description='系统名称') + mdl_name: Optional[str] = Field(default=None, description='模式名称') + tab_name: Optional[str] = Field(default=None, description='表名') + + +class ColumnSuppleModel(BaseModel): + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) + fld_eng_name: Optional[str] = None + fld_crrct_name: Optional[str] = None + crrct_pk_flag: Optional[int] = None + fld_desc: Optional[str] = None + pic: Optional[str] = None + fld_clas: Optional[str] = None + fld_null_rate: Optional[str] = None + rec_stat: Optional[str] = None + + +class SuppleModel(BaseModel): + model_config = ConfigDict(alias_generator=to_camel, from_attributes=True) + ssys_cd: Optional[str] = None + mdl_name: Optional[str] = None + tab_eng_name: Optional[str] = None + tab_crrct_name: Optional[str] = None + tab_desc: Optional[str] = None + pic: Optional[str] = None + gov_flag: Optional[str] = None + rec_stat: Optional[str] = None + tab_clas: Optional[str] = None + columnInfo: Optional[List[ColumnSuppleModel]] = None diff --git a/vue-fastapi-backend/module_admin/service/approval_service.py b/vue-fastapi-backend/module_admin/service/approval_service.py new file mode 100644 index 0000000..1235c5e --- /dev/null +++ b/vue-fastapi-backend/module_admin/service/approval_service.py @@ -0,0 +1,121 @@ +import json +import uuid + +from typing import Optional +from sqlalchemy.ext.asyncio import AsyncSession +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.approval_vo import ApplyModel, OperateModel, ApprovalQueryObject, EditObjectModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.entity.do.approval_do import FlowApproval +from exceptions.exception import ServiceException, ServiceWarning +from datetime import datetime +from utils.common_util import CamelCaseUtil +from module_admin.dao.approval_dao import ApprovalDao +from module_admin.dao.meta_dao import MetaDao + + +class ApprovalService: + """ + 智能问答服务层 + """ + + @classmethod + async def apply_services(cls, result_db: AsyncSession, apply: ApplyModel): + flow_approval = FlowApproval() + flow_approval.id = uuid.uuid4() + flow_approval.businessType = apply.businessType + flow_approval.businessId = apply.businessId + flow_approval.applicant = apply.applicant + flow_approval.applyTime = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + flow_approval.status = 'waiting' + # todo 后期进行流程配置,角色 or 人员 下一步审批人 + flow_approval.approver = 'admin' + flow_approval.nextStep = '1' + await ApprovalDao.add_flow_approval(result_db, flow_approval) + await result_db.commit() + return CrudResponseModel(is_success=True, message='申请成功') + + @classmethod + async def operate_services(cls, result_db: AsyncSession, operate: OperateModel, current_user: CurrentUserModel): + flow_approval = await ApprovalDao.get_flow_by_id(result_db, operate.flowId) + if flow_approval is None: + raise ServiceException(message=f'所操作的流程不存在') + if flow_approval.status == 'succeed' or flow_approval.status == 'rejected': + raise ServiceException(message='所操作的流程已结束') + if flow_approval.status == 'canceled': + raise ServiceException(message='所操作的流程已撤回') + array = [] + if flow_approval.approvalFlow is not None: + array = json.loads(flow_approval.approvalFlow) + array.append({'operator': current_user.user.user_name, + 'operateTime': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), + 'operate': operate.operateType, + 'operateComment': operate.operateComment, + }) + edit = EditObjectModel() + edit.id = flow_approval.id + edit.approvalFlow = json.dumps(array) + if operate.operateType == 'success': + # todo 增加流程配置,并查询出下一步操作人以及步骤 + edit.status = 'succeed' # 有下一步执行人,则设置为 pending + edit.approver = None + edit.nextStep = -1 + if operate.operateType == 'reject': + edit.status = 'rejected' + edit.approver = None + edit.nextStep = -1 + if flow_approval.businessType == 't_metadata_supp_info': + await cls.syncSuppInfo(result_db, flow_approval.businessId, operate.operateType) + await ApprovalDao.edit_flow_approval(result_db, edit.model_dump(exclude_unset=True)) + await result_db.commit() + return CrudResponseModel(is_success=True, message='操作成功') + + @classmethod + async def syncSuppInfo(cls, result_db: AsyncSession, suppId: str, operateType: str): + table = await MetaDao.get_supp_table_vett_by_id(suppId, result_db) + if table is None: + raise ServiceException(message='所查询的业务数据不存在') + if table.apply_status == 'succeed' or table.apply_status == 'rejected': + raise ServiceException(message='所改业务已审核完毕') + column_list = await MetaDao.get_meta_col_supp_vett(table, result_db) + if column_list is not None and len(column_list) > 0: + for column in column_list: + column.apply_status = operateType + suppColumn = await MetaDao.get_supp_column_by_vett(column, result_db) + await MetaDao.updateMetadataFldSuppInfoVett(column.onum, operateType, result_db) + if suppColumn is None: + await MetaDao.insertMetadataFldSuppInfo(column, result_db) + else: + await MetaDao.updateMetadataFldSuppInfo(suppColumn.onum, column, result_db) + suppTable = await MetaDao.get_supp_table_by_vett(table.ssys_cd, table.mdl_name, table.tab_eng_name, result_db) + await MetaDao.updateMetadataSuppInfoVett(table.onum, operateType, result_db) + if suppTable is None: + await MetaDao.insertMetadataSuppInfo(table, result_db) + else: + await MetaDao.updateMetadataSuppInfo(suppTable.onum, table, result_db) + return CrudResponseModel(is_success=True, message='操作成功') + + @classmethod + async def get_flow_list_services(cls, query_db: AsyncSession, query_param: ApprovalQueryObject, + current_user: CurrentUserModel): + result = await ApprovalDao.get_flow_list(query_db, query_param, current_user) + return result + + @classmethod + async def get_waiting_total_services(cls, query_db: AsyncSession, current_user: CurrentUserModel): + result = await ApprovalDao.get_waiting_total(query_db, current_user) + return result + + @classmethod + async def cancel_apply_services(cls, query_db: AsyncSession, flow_id: str, + current_user: CurrentUserModel): + flow = await ApprovalDao.get_flow_by_idAndUser(flow_id, current_user.user.user_name) + if flow is None: + raise ServiceException(message=f'所操作的流程不存在') + if flow.status == 'succeed' or flow.status == 'rejected': + raise ServiceException(message='所操作的流程已结束,无需撤回') + if flow.status == 'canceled': + raise ServiceException(message='所操作的流程已撤回,无需重复操作') + flow.status = 'canceled' + await ApprovalDao.edit_flow_approval(query_db, flow) + return CrudResponseModel(is_success=True, message='操作成功') diff --git a/vue-fastapi-backend/module_admin/service/meta_service.py b/vue-fastapi-backend/module_admin/service/meta_service.py new file mode 100644 index 0000000..db5df8d --- /dev/null +++ b/vue-fastapi-backend/module_admin/service/meta_service.py @@ -0,0 +1,126 @@ +import uuid + +from module_admin.entity.vo.meta_vo import MetaPageObject, MetaColObject, SuppleModel +from module_admin.entity.do.meta_do import MetadataSuppInfo, MetadataFldSuppInfo, MetadataSuppInfoVett, \ + MetadataFldSuppInfoVett +from module_admin.dao.meta_dao import MetaDao +from datetime import datetime +from module_admin.entity.vo.user_vo import CurrentUserModel +from module_admin.entity.vo.approval_vo import ApplyModel +from sqlalchemy.ext.asyncio import AsyncSession +from exceptions.exception import ServiceException, ServiceWarning +from utils.pwd_util import * +from utils.common_util import * +from utils.log_util import logger +from module_admin.service.login_service import LoginService +from module_admin.service.approval_service import ApprovalService + +from module_admin.entity.vo.common_vo import CrudResponseModel +from module_admin.entity.vo.user_vo import CurrentUserModel +from utils.common_util import CamelCaseUtil +import re + + +class MetaService: + + @classmethod + async def get_meta_list_services(cls, result_db: AsyncSession, query_object: MetaPageObject, + current_user: CurrentUserModel): + """ + 获取元信息service + :param result_db: orm对象 + :param query_object: 查询参数对象 + :param data_scope_sql: 数据权限对应的查询sql语句 + :return: 用户列表信息对象 + """ + # print("********") + # 0,正常,1已发布,2审核中,3已审核,4已作废 + if 'admin' in current_user.roles: + meta_rel_list = await MetaDao.get_meta_rel_list(result_db, query_object) + return meta_rel_list + else: + # meta_rel_list = MetaDao.get_meta_rel_list(result_db, query_object, data_scope_sql) + return None + + @classmethod + async def get_meta_col_list_services(cls, result_db: AsyncSession, query_object: MetaColObject): + meta_result = await MetaDao.get_meta_col_list(result_db, query_object) + return cls.convert_json_keys(meta_result) + + @classmethod + async def get_meta_clas_list_services(cls, result_db: AsyncSession): + result = await MetaDao.get_meta_clas_list(result_db) + return CamelCaseUtil.transform_result(result) + + @classmethod + async def meta_supp(cls, result_db: AsyncSession, supple: SuppleModel, current_user: CurrentUserModel): + # 0,暂存 waiting,申请中,pending审核中,succeed,rejected已审核,canceled已取消 + hasTable = await MetaDao.get_lastest_meta_data_supp_vett(result_db, supple.ssys_cd, supple.mdl_name, + supple.tab_eng_name) + tableOnum = uuid.uuid4() + if hasTable is not None: + if hasTable.apply_status == 'waiting': + raise ServiceException(message=f'所补录对象已存在补录待审核记录,请等待审批完成或撤回申请后,再行补录') + if hasTable.apply_status == 'pending': + raise ServiceException(message=f'所补录对象已存在待审核记录,请等待审批完成后,再行补录') + suppTableInfo = MetadataSuppInfoVett() + suppTableInfo.onum = tableOnum + suppTableInfo.ssys_cd = supple.ssys_cd + suppTableInfo.mdl_name = supple.mdl_name + suppTableInfo.tab_eng_name = supple.tab_eng_name + suppTableInfo.tab_crrct_name = supple.tab_crrct_name + suppTableInfo.tab_desc = supple.tab_desc + suppTableInfo.pic = supple.pic + suppTableInfo.gov_flag = supple.gov_flag + suppTableInfo.tab_clas = supple.tab_clas + suppTableInfo.rec_subm_prsn = current_user.user.user_name + suppTableInfo.apply_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + suppTableInfo.apply_status = 'waiting' + await MetaDao.insertMetadataSuppInfoVett(suppTableInfo, result_db) + await result_db.commit() + if supple.columnInfo is not None and len(supple.columnInfo) > 0: + for column in supple.columnInfo: + suppColumnInfo = MetadataFldSuppInfoVett() + suppColumnInfo.onum = uuid.uuid4() + suppColumnInfo.ssys_cd = supple.ssys_cd + suppColumnInfo.mdl_name = supple.mdl_name + suppColumnInfo.tab_eng_name = supple.tab_eng_name + suppColumnInfo.fld_eng_name = column.fld_eng_name + suppColumnInfo.fld_crrct_name = column.fld_crrct_name + suppColumnInfo.crrct_pk_flag = column.crrct_pk_flag + suppColumnInfo.fld_desc = column.fld_desc + suppColumnInfo.pic = column.pic + suppColumnInfo.fld_clas = column.fld_clas + suppColumnInfo.fld_null_rate = column.fld_null_rate + suppColumnInfo.rec_stat = column.rec_stat + suppColumnInfo.rec_subm_prsn = current_user.user.user_name + suppColumnInfo.apply_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + suppColumnInfo.apply_status = 'waiting' + await MetaDao.insertMetadataFldSuppInfoVett(suppColumnInfo, result_db) + await result_db.commit() + applyModel = ApplyModel() + applyModel.businessType = "t_metadata_supp_info" + applyModel.businessId = tableOnum + applyModel.applicant = current_user.user.user_name + await ApprovalService.apply_services(result_db, applyModel) + return CrudResponseModel(is_success=True, message='操作成功') + + @classmethod + def snake_to_camel(cls, snake_str: str): + # 将字符串按下划线分割成列表 + components = snake_str.split('_') + # 第一个单词保持小写,后续单词首字母大写 + camel_str = components[0] + ''.join(word.capitalize() for word in components[1:]) + return camel_str + + @classmethod + def convert_json_keys(cls, data): + if isinstance(data, dict): + # 如果数据是字典,则转换键名并递归处理值 + return {cls.snake_to_camel(k): cls.convert_json_keys(v) for k, v in data.items()} + elif isinstance(data, list): + # 如果数据是列表,则递归处理列表中的每个元素 + return [cls.convert_json_keys(element) for element in data] + else: + # 如果数据不是字典或列表,则直接返回(即基本数据类型,如字符串、数字等) + return data diff --git a/vue-fastapi-backend/server.py b/vue-fastapi-backend/server.py index ed6968a..e80a196 100644 --- a/vue-fastapi-backend/server.py +++ b/vue-fastapi-backend/server.py @@ -24,7 +24,9 @@ from module_admin.controller.server_controller import serverController from module_admin.controller.user_controller import userController from module_admin.controller.aichat_controller import aichatController from module_admin.controller.metatask_controller import metataskController +from module_admin.controller.meta_controller import metaController from module_admin.controller.metasecurity_controller import metaSecurityController +from module_admin.controller.approval_controller import approvalController from sub_applications.handle import handle_sub_applications from utils.common_util import worship from utils.log_util import logger @@ -83,6 +85,8 @@ controller_list = [ {'router': metataskController, 'tags': ['元数据管理-元数据任务模块']}, {'router': metaSecurityController, 'tags': ['元数据管理-数据安全']}, {'router': aichatController, 'tags': ['智能问答模块']}, + {'router': metaController, 'tags': ['元数据信息模块']}, + {'router': approvalController, 'tags': ['审批模块']}, ] for controller in controller_list: diff --git a/vue-fastapi-frontend/package.json b/vue-fastapi-frontend/package.json index a306739..e981d5b 100644 --- a/vue-fastapi-frontend/package.json +++ b/vue-fastapi-frontend/package.json @@ -24,6 +24,7 @@ "@vueuse/core": "10.11.0", "ant-design-vue": "^4.1.1", "axios": "0.28.1", + "codemirror-editor-vue3": "^2.8.0", "echarts": "5.5.1", "element-plus": "2.8.0", "file-saver": "2.0.5", @@ -36,6 +37,7 @@ "nprogress": "0.2.0", "pinia": "2.1.7", "remixicon": "^4.6.0", + "sql-formatter": "^15.4.10", "uuid": "^11.0.4", "vue": "3.4.15", "vue-clipboard3": "^2.0.0", diff --git a/vue-fastapi-frontend/src/api/aichat/aichat.js b/vue-fastapi-frontend/src/api/aichat/aichat.js index 52097a3..c0b15e2 100644 --- a/vue-fastapi-frontend/src/api/aichat/aichat.js +++ b/vue-fastapi-frontend/src/api/aichat/aichat.js @@ -8,7 +8,7 @@ export function listChatHistory(sessionId) { sessionId = '0' } return request({ - url: '/aichat/session/list/'+sessionId, + url: '/default-api/aichat/session/list/'+sessionId, method: 'get', params: {} }) diff --git a/vue-fastapi-frontend/src/api/flow/flow.js b/vue-fastapi-frontend/src/api/flow/flow.js new file mode 100644 index 0000000..5249b41 --- /dev/null +++ b/vue-fastapi-frontend/src/api/flow/flow.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + + +export function getApprovalList(data) { + return request({ + url: '/default-api/approval/list', + method: 'get', + params: data + }) +} + +export function getWaitingFlowCount() { + return request({ + url: '/default-api/approval/waitingTotal', + method: 'get' + }) +} + +export function operateProcess(data) { + return request({ + url: '/default-api/approval/operate', + method: 'post', + data: data + }) +} \ No newline at end of file diff --git a/vue-fastapi-frontend/src/api/meta/metaInfo.js b/vue-fastapi-frontend/src/api/meta/metaInfo.js new file mode 100644 index 0000000..d2ae8cb --- /dev/null +++ b/vue-fastapi-frontend/src/api/meta/metaInfo.js @@ -0,0 +1,46 @@ +import request from '@/utils/request' + +// 查询参数列表 +export function getDataSourceList(query) { + return request({ + url: '/ds-api/dolphinscheduler/datasources/withpwdlist?pageNo=1&pageSize=100', + method: 'get', + headers: {dashUserName:query.userName,dashPassword:query.password} + }) +} +// 查询参数列表 +export function getMetaDataList(query) { + return request({ + url: '/default-api/dasset/meta/get', + method: 'get', + params: query + }) +} + +export function getColumnList(query){ + return request({ + url:'/default-api/dasset/meta/column/list', + method: 'get', + params: query + }) +} + +export function getMetaClasList(){ + return request({ + url:'/default-api/dasset/meta/clas/list', + method: 'get', + }) +} + +export function postMetaSupp(data){ + return request({ + url:'/default-api/dasset/meta/supp', + method: 'post', + data: data + }) +} + + + + + diff --git a/vue-fastapi-frontend/src/components/TopNav/index.vue b/vue-fastapi-frontend/src/components/TopNav/index.vue index 52b40ea..b2594db 100644 --- a/vue-fastapi-frontend/src/components/TopNav/index.vue +++ b/vue-fastapi-frontend/src/components/TopNav/index.vue @@ -44,7 +44,7 @@ const visibleNumber = ref(null); // 当前激活菜单的 index const currentIndex = ref(null); // 隐藏侧边栏路由 -const hideList = ['/index', '/user/profile']; +const hideList = ['/index', '/user/profile', 'system/flow/index']; const appStore = useAppStore() const settingsStore = useSettingsStore() diff --git a/vue-fastapi-frontend/src/components/codemirror/SQLCodeMirror.vue b/vue-fastapi-frontend/src/components/codemirror/SQLCodeMirror.vue new file mode 100644 index 0000000..eb817ca --- /dev/null +++ b/vue-fastapi-frontend/src/components/codemirror/SQLCodeMirror.vue @@ -0,0 +1,72 @@ + + + + + \ No newline at end of file diff --git a/vue-fastapi-frontend/src/layout/components/Navbar.vue b/vue-fastapi-frontend/src/layout/components/Navbar.vue index 05e15af..75db2de 100644 --- a/vue-fastapi-frontend/src/layout/components/Navbar.vue +++ b/vue-fastapi-frontend/src/layout/components/Navbar.vue @@ -8,8 +8,13 @@