Browse Source

Merge remote-tracking branch 'origin/master'

master
xueyinfei 1 week ago
parent
commit
b4971369d9
  1. 3
      vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py
  2. 145
      vue-fastapi-backend/module_admin/controller/metadata_config_controller.py
  3. 116
      vue-fastapi-backend/module_admin/dao/metadata_config_dao.py
  4. 1
      vue-fastapi-backend/module_admin/entity/do/meta_do.py
  5. 33
      vue-fastapi-backend/module_admin/entity/do/metadata_config_do.py
  6. 106
      vue-fastapi-backend/module_admin/entity/vo/metadata_config_vo.py
  7. 162
      vue-fastapi-backend/module_admin/service/metadata_config_service.py
  8. 3
      vue-fastapi-backend/module_admin/service/metasecurity_service.py
  9. 2
      vue-fastapi-backend/server.py
  10. 88
      vue-fastapi-frontend/src/api/metadataConfig/metadataConfig.js
  11. 15
      vue-fastapi-frontend/src/store/modules/user.js
  12. 62
      vue-fastapi-frontend/src/views/dataAsset/directory/index.vue
  13. 301
      vue-fastapi-frontend/src/views/metadataConfig/clas/index.vue
  14. 293
      vue-fastapi-frontend/src/views/metadataConfig/sec/index.vue

3
vue-fastapi-backend/module_admin/controller/data_ast_content_controller.py

@ -108,6 +108,9 @@ async def getMetaSercuityData(
apiModel.dbRCode = dataAstSecuRequest.data_ast_src
apiModel.username = user_name
apiModel.password = password
apiModel.isPage = True
apiModel.pageNum = 1
apiModel.pageSize = 10
apiModel.sqlStr = "select * from " + dataAstSecuRequest.data_ast_eng_name
# logger.info(f"设置 apiModel 参数:dbRId={apiModel.dbRId}, username={apiModel.username}, password={apiModel.password}, sqlStr={apiModel.sqlStr}")

145
vue-fastapi-backend/module_admin/controller/metadata_config_controller.py

@ -0,0 +1,145 @@
from datetime import datetime
from fastapi import APIRouter, Depends, Request, Form
from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel,MetadataSecModel,MetadataSecPageQueryModel
from module_admin.service.metadata_config_service import MetadataConfigService
from config.get_db import get_db
from utils.response_util import ResponseUtil
from utils.page_util import PageResponseModel
from utils.log_util import logger
from module_admin.service.login_service import LoginService
from module_admin.entity.vo.user_vo import CurrentUserModel
metadataConfigController = APIRouter(prefix="/metadataConfig")
@metadataConfigController.get("/clas/list", response_model=PageResponseModel)
async def get_metadata_clas_list(
request: Request,
query: MetadataClasPageQueryModel = Depends(MetadataClasPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.get_metadata_clas_list_services(query_db, query, is_page=True)
logger.info("获取元数据分类列表成功")
return ResponseUtil.success(model_content=result)
@metadataConfigController.post("/clas")
@ValidateFields(validate_model="add_metadata_clas")
async def add_metadata_clas(
request: Request,
add_clas: MetadataClasModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_clas.upd_time = datetime.now()
add_clas.rec_subm_prsn = current_user.user.user_name
# 这里没有用户信息,若需要创建人信息可自行补充
result = await MetadataConfigService.add_metadata_clas_services(query_db, add_clas)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.put("/clas")
@ValidateFields(validate_model="edit_metadata_clas")
async def edit_metadata_clas(
request: Request,
edit_clas: MetadataClasModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_clas.upd_time = datetime.now()
edit_clas.rec_subm_prsn = current_user.user.user_name
result = await MetadataConfigService.edit_metadata_clas_services(query_db, edit_clas)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.delete("/clas/{clas_ids}")
async def delete_metadata_clas(
request: Request,
clas_ids: str,
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.delete_metadata_clas_services(query_db, clas_ids)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.get("/clas/{clas_id}", response_model=MetadataClasModel)
async def get_metadata_clas_detail(
request: Request,
clas_id: int,
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.get_metadata_clas_detail_services(query_db, clas_id)
logger.info(f"获取元数据分类ID={clas_id}详情成功")
return ResponseUtil.success(data=result)
# ------------------------ MetadataSec 控制接口 ------------------------ #
@metadataConfigController.get("/sec/list", response_model=PageResponseModel)
async def get_metadata_sec_list(
request: Request,
query: MetadataSecPageQueryModel = Depends(MetadataSecPageQueryModel.as_query),
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.get_metadata_sec_list_services(query_db, query, is_page=True)
logger.info("获取数据安全配置列表成功")
return ResponseUtil.success(model_content=result)
@metadataConfigController.post("/sec")
@ValidateFields(validate_model="add_metadata_sec")
async def add_metadata_sec(
request: Request,
add_sec: MetadataSecModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
add_sec.upd_time = datetime.now()
add_sec.rec_subm_prsn = current_user.user.user_name
result = await MetadataConfigService.add_metadata_sec_services(query_db, add_sec)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.put("/sec")
@ValidateFields(validate_model="edit_metadata_sec")
async def edit_metadata_sec(
request: Request,
edit_sec: MetadataSecModel,
query_db: AsyncSession = Depends(get_db),
current_user: CurrentUserModel = Depends(LoginService.get_current_user),
):
edit_sec.upd_time = datetime.now()
edit_sec.rec_subm_prsn = current_user.user.user_name
result = await MetadataConfigService.edit_metadata_sec_services(query_db, edit_sec)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.delete("/sec/{sec_ids}")
async def delete_metadata_sec(
request: Request,
sec_ids: str,
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.delete_metadata_sec_services(query_db, sec_ids)
logger.info(result.message)
return ResponseUtil.success(msg=result.message)
@metadataConfigController.get("/sec/{sec_id}", response_model=MetadataSecModel)
async def get_metadata_sec_detail(
request: Request,
sec_id: str,
query_db: AsyncSession = Depends(get_db),
):
result = await MetadataConfigService.get_metadata_sec_detail_services(query_db, sec_id)
logger.info(f"获取数据安全配置 onum={sec_id} 详情成功")
return ResponseUtil.success(data=result)

116
vue-fastapi-backend/module_admin/dao/metadata_config_dao.py

@ -0,0 +1,116 @@
from datetime import datetime, time
from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.meta_do import MetadataClas # ORM 类
from module_admin.entity.do.metadata_config_do import MetadataSec # ORM 类
class MetadataConfigDao:
"""
标签信息数据库操作层
"""
@classmethod
async def get_clas_detail_by_id(cls, db: AsyncSession, clas_id: int):
"""
根据标签序号获取标签详细信息
"""
result = await db.execute(select(MetadataClas).where(MetadataClas.clas_onum == clas_id))
return result.scalars().first()
@classmethod
async def get_clas_detail_by_info(cls, db: AsyncSession, clas):
"""
根据标签参数获取标签信息根据 MetadataClasModel 实例
"""
result = await db.execute(
select(MetadataClas).where(
MetadataClas.clas_name == clas.clas_name if clas.clas_name else True,
MetadataClas.clas_eff_flag == clas.clas_eff_flag if clas.clas_eff_flag else True,
)
)
return result.scalars().first()
@classmethod
async def get_metadata_clas_list(cls, db: AsyncSession, query_object, is_page: bool = False):
"""
获取标签信息列表支持分页
"""
query = select(MetadataClas).where(
MetadataClas.clas_pri_clas.like(f"%{query_object.clas_pri_clas}%") if query_object.clas_pri_clas else True,
MetadataClas.clas_scd_clas.like(f"%{query_object.clas_scd_clas}%") if query_object.clas_scd_clas else True,
MetadataClas.clas_thre_clas.like(f"%{query_object.clas_thre_clas}%") if query_object.clas_thre_clas else True,
MetadataClas.clas_name.like(f"%{query_object.clas_name}%") if query_object.clas_name else True,
MetadataClas.clas_eff_flag == query_object.clas_eff_flag if query_object.clas_eff_flag else True,
MetadataClas.upd_time.between(
datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(0, 0, 0)),
datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)),
)
if query_object.begin_time and query_object.end_time else True,
).order_by(MetadataClas.clas_onum).distinct()
from utils.page_util import PageUtil
return await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
@classmethod
async def add_metadata_clas_dao(cls, db: AsyncSession, clas):
"""
新增标签信息
"""
db_clas = MetadataClas(**clas.model_dump())
db.add(db_clas)
await db.flush()
return db_clas
@classmethod
async def edit_metadata_clas_dao(cls, db: AsyncSession, clas_id: int, update_data: dict):
"""
修改标签信息
"""
await db.execute(
update(MetadataClas)
.where(MetadataClas.clas_onum == clas_id)
.values(**update_data)
)
@classmethod
async def delete_metadata_clas_dao(cls, db: AsyncSession, clas_onum_list: list[int]):
"""
删除标签信息支持批量
"""
await db.execute(delete(MetadataClas).where(MetadataClas.clas_onum.in_(clas_onum_list)))
@classmethod
async def get_sec_detail_by_id(cls, db: AsyncSession, onum: str):
result = await db.execute(select(MetadataSec).where(MetadataSec.onum == onum))
return result.scalars().first()
@classmethod
async def get_metadata_sec_list(cls, db: AsyncSession, query_object, is_page: bool = False):
query = select(MetadataSec).where(
MetadataSec.sec_level_name.like(f"%{query_object.sec_level_name}%") if query_object.sec_level_name else True,
MetadataSec.sec_eff_flag == query_object.sec_eff_flag if query_object.sec_eff_flag else True,
MetadataSec.upd_time.between(
datetime.combine(datetime.strptime(query_object.begin_time, '%Y-%m-%d'), time(0, 0, 0)),
datetime.combine(datetime.strptime(query_object.end_time, '%Y-%m-%d'), time(23, 59, 59)),
) if query_object.begin_time and query_object.end_time else True,
).order_by(MetadataSec.upd_time.desc()).distinct()
from utils.page_util import PageUtil
return await PageUtil.paginate(db, query, query_object.page_num, query_object.page_size, is_page)
@classmethod
async def add_metadata_sec_dao(cls, db: AsyncSession, sec):
db_sec = MetadataSec(**sec.model_dump())
db.add(db_sec)
await db.flush()
return db_sec
@classmethod
async def edit_metadata_sec_dao(cls, db: AsyncSession, onum: str, update_data: dict):
await db.execute(
update(MetadataSec).where(MetadataSec.onum == onum).values(**update_data)
)
@classmethod
async def delete_metadata_sec_dao(cls, db: AsyncSession, onum_list: list[str]):
await db.execute(delete(MetadataSec).where(MetadataSec.onum.in_(onum_list)))

1
vue-fastapi-backend/module_admin/entity/do/meta_do.py

@ -80,6 +80,7 @@ class MetadataClas(Base):
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_tmpl = Column(String(200, 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无效)')

33
vue-fastapi-backend/module_admin/entity/do/metadata_config_do.py

@ -0,0 +1,33 @@
from datetime import datetime
from sqlalchemy import Column, String, Integer, DateTime, TIMESTAMP, func
from config.database import Base
# class MetadataClas(Base):
# """
# 标签信息表
# """
# __tablename__ = 't_metadata_clas'
# clas_onum = Column(Integer, primary_key=True, default=0, comment='标签序号')
# clas_pri_clas = Column(String(50), default=None, comment='标签一级分类')
# clas_scd_clas = Column(String(50), default=None, comment='标签二级分类')
# clas_thre_clas = Column(String(50), default=None, comment='标签三级分类')
# clas_name = Column(String(200), default=None, comment='标签名称')
# clas_tmpl = Column(String(200), default=None, comment='标签模版')
# clas_eff_flag = Column(String(1), default=None, comment='标签有效标志')
# rec_subm_prsn = Column(String(64), default=None, comment='记录提交人')
# upd_time = Column(TIMESTAMP, default=func.now(), onupdate=func.now(), nullable=True, comment='更新时间')
class MetadataSec(Base):
"""
数据安全配置表
"""
__tablename__ = 't_metadata_sec'
onum = Column(String(36), primary_key=True, comment='唯一编号')
sec_eff_flag = Column(String(1), default=None, comment='有效标志')
rec_subm_prsn = Column(String(64), default=None, comment='记录提交人')
upd_time = Column(TIMESTAMP, default=func.now(), onupdate=func.now(), nullable=True, comment='更新时间')
sec_level_name = Column(String(50), default=None, comment='等级名称')
sec_level_desc = Column(String(200), default=None, comment='等级说明')
sec_level_summary = Column(String(200), comment='等级简介')

106
vue-fastapi-backend/module_admin/entity/vo/metadata_config_vo.py

@ -0,0 +1,106 @@
from datetime import datetime
from pydantic import BaseModel, ConfigDict, Field
from pydantic.alias_generators import to_camel
from pydantic_validation_decorator import NotBlank, Size
from typing import Literal, Optional
from module_admin.annotation.pydantic_annotation import as_query
class MetadataClasModel(BaseModel):
"""
标签信息表对应 Pydantic 模型
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
clas_onum: Optional[int] = Field(default=None, description='标签序号')
clas_pri_clas: Optional[str] = Field(default=None, description='标签一级分类')
clas_scd_clas: Optional[str] = Field(default=None, description='标签二级分类')
clas_thre_clas: Optional[str] = Field(default=None, description='标签三级分类')
clas_name: Optional[str] = Field(default=None, description='标签名称')
clas_tmpl: Optional[str] = Field(default=None, description='标签模版')
clas_eff_flag: Optional[Literal['0', '1']] = Field(default=None, description='标签有效标志')
rec_subm_prsn: Optional[str] = Field(default=None, description='记录提交人')
upd_time: Optional[datetime] = Field(default=None, description='更新时间')
@NotBlank(field_name='clas_name', message='标签名称不能为空')
@Size(field_name='clas_name', min_length=1, max_length=200, message='标签名称长度不能超过200个字符')
def get_clas_name(self):
return self.clas_name
def validate_fields(self):
self.get_clas_name()
class MetadataClasQueryModel(MetadataClasModel):
"""
标签信息不分页查询模型
"""
begin_time: Optional[str] = Field(default=None, description='开始时间')
end_time: Optional[str] = Field(default=None, description='结束时间')
@as_query
class MetadataClasPageQueryModel(MetadataClasQueryModel):
"""
标签信息分页查询模型
"""
page_num: int = Field(default=1, description='当前页码')
page_size: int = Field(default=10, description='每页记录数')
class DeleteMetadataClasModel(BaseModel):
"""
删除标签信息模型
"""
model_config = ConfigDict(alias_generator=to_camel)
clas_onums: str = Field(description='需要删除的标签主键(多个用逗号分隔)')
class MetadataSecModel(BaseModel):
"""
数据安全配置表对应 Pydantic 模型
"""
model_config = ConfigDict(alias_generator=to_camel, from_attributes=True)
onum: Optional[str] = Field(default=None, description='唯一编号')
sec_eff_flag: Optional[Literal['0', '1']] = Field(default=None, description='有效标志')
rec_subm_prsn: Optional[str] = Field(default=None, description='记录提交人')
upd_time: Optional[datetime] = Field(default=None, description='更新时间')
sec_level_name: Optional[str] = Field(default=None, description='等级名称')
sec_level_desc: Optional[str] = Field(default=None, description='等级说明')
sec_level_summary: Optional[str] = Field(default=None, description='等级简介')
@NotBlank(field_name='sec_level_name', message='等级名称不能为空')
@Size(field_name='sec_level_name', min_length=1, max_length=50, message='等级名称长度不能超过50个字符')
def get_sec_level_name(self):
return self.sec_level_name
def validate_fields(self):
self.get_sec_level_name()
class DeleteMetadataSecModel(BaseModel):
"""
删除数据安全配置模型
"""
model_config = ConfigDict(alias_generator=to_camel)
onums: str = Field(description='需要删除的唯一编号(多个用逗号分隔)')
class MetadataSecQueryModel(MetadataSecModel):
"""
数据安全配置不分页查询模型
"""
begin_time: Optional[str] = Field(default=None, description='开始时间')
end_time: Optional[str] = Field(default=None, description='结束时间')
@as_query
class MetadataSecPageQueryModel(MetadataSecQueryModel):
"""
数据安全配置分页查询模型
"""
page_num: int = Field(default=1, description='当前页码')
page_size: int = Field(default=10, description='每页记录数')

162
vue-fastapi-backend/module_admin/service/metadata_config_service.py

@ -0,0 +1,162 @@
from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.dao.metadata_config_dao import MetadataConfigDao
from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel,MetadataSecModel,MetadataSecPageQueryModel
from utils.common_util import CamelCaseUtil
from exceptions.exception import ServiceException
import uuid
class MetadataConfigService:
"""
元数据分类管理 Service
"""
@classmethod
async def get_metadata_clas_list_services(
cls, query_db: AsyncSession, query_object: MetadataClasPageQueryModel, is_page: bool = False
):
"""
查询元数据分类列表
"""
result = await MetadataConfigDao.get_metadata_clas_list(query_db, query_object, is_page)
return result
@classmethod
async def add_metadata_clas_services(
cls, query_db: AsyncSession, page_object: MetadataClasModel
):
"""
新增元数据分类
"""
try:
await MetadataConfigDao.add_metadata_clas_dao(query_db, page_object)
await query_db.commit()
return CrudResponseModel(is_success=True, message="新增成功")
except Exception as e:
await query_db.rollback()
raise e
@classmethod
async def edit_metadata_clas_services(
cls, query_db: AsyncSession, page_object: MetadataClasModel
):
"""
编辑元数据分类
"""
edit_data = page_object.model_dump(exclude_unset=True)
info = await cls.get_metadata_clas_detail_services(query_db, page_object.clas_onum)
if info.clas_onum:
try:
await MetadataConfigDao.edit_metadata_clas_dao(query_db, page_object.clas_onum, edit_data)
await query_db.commit()
return CrudResponseModel(is_success=True, message="更新成功")
except Exception as e:
await query_db.rollback()
raise e
else:
raise ServiceException(message="元数据标签不存在")
@classmethod
async def delete_metadata_clas_services(
cls, query_db: AsyncSession, clas_ids: str
):
"""
删除元数据分类支持多个ID用逗号分隔
"""
if not clas_ids:
raise ServiceException(message="传入的分类ID为空")
id_list = [int(id_str) for id_str in clas_ids.split(",") if id_str.isdigit()]
if not id_list:
raise ServiceException(message="无效的分类ID列表")
try:
await MetadataConfigDao.delete_metadata_clas_dao(query_db, id_list)
await query_db.commit()
return CrudResponseModel(is_success=True, message="删除成功")
except Exception as e:
await query_db.rollback()
raise e
@classmethod
async def get_metadata_clas_detail_services(cls, query_db: AsyncSession, clas_id: int):
"""
查询元数据分类详情
"""
result = await MetadataConfigDao.get_clas_detail_by_id(query_db, clas_id)
if result:
return MetadataClasModel(**CamelCaseUtil.transform_result(result))
else:
return MetadataClasModel(**dict())
@classmethod
async def get_metadata_sec_list_services(
cls, query_db: AsyncSession, query_object: MetadataSecPageQueryModel, is_page: bool = False
):
"""
查询数据安全配置列表
"""
result = await MetadataConfigDao.get_metadata_sec_list(query_db, query_object, is_page)
return result
@classmethod
async def add_metadata_sec_services(cls, query_db: AsyncSession, page_object: MetadataSecModel):
"""
新增数据安全配置
"""
try:
page_object.onum=str(uuid.uuid4())
await MetadataConfigDao.add_metadata_sec_dao(query_db, page_object)
await query_db.commit()
return CrudResponseModel(is_success=True, message="新增成功")
except Exception as e:
await query_db.rollback()
raise e
@classmethod
async def edit_metadata_sec_services(cls, query_db: AsyncSession, page_object: MetadataSecModel):
"""
编辑数据安全配置
"""
edit_data = page_object.model_dump(exclude_unset=True)
info = await cls.get_metadata_sec_detail_services(query_db, page_object.onum)
if info.onum:
try:
await MetadataConfigDao.edit_metadata_sec_dao(query_db, page_object.onum, edit_data)
await query_db.commit()
return CrudResponseModel(is_success=True, message="更新成功")
except Exception as e:
await query_db.rollback()
raise e
else:
raise ServiceException(message="数据安全配置不存在")
@classmethod
async def delete_metadata_sec_services(cls, query_db: AsyncSession, onum_list: str):
"""
删除数据安全配置支持多个编号用逗号分隔
"""
if not onum_list:
raise ServiceException(message="传入的编号为空")
id_list = [onum.strip() for onum in onum_list.split(",") if onum.strip()]
if not id_list:
raise ServiceException(message="无效的编号列表")
try:
await MetadataConfigDao.delete_metadata_sec_dao(query_db, id_list)
await query_db.commit()
return CrudResponseModel(is_success=True, message="删除成功")
except Exception as e:
await query_db.rollback()
raise e
@classmethod
async def get_metadata_sec_detail_services(cls, query_db: AsyncSession, onum: str):
"""
查询数据安全配置详情
"""
result = await MetadataConfigDao.get_sec_detail_by_id(query_db, onum)
if result:
return MetadataSecModel(**CamelCaseUtil.transform_result(result))
else:
return MetadataSecModel(**dict())

3
vue-fastapi-backend/module_admin/service/metasecurity_service.py

@ -306,8 +306,9 @@ class MetaSecurityService:
# await test_connection(dbConnent)
#3获取sql中涉及的表名
sqlScheamAndTable =await cls.get_tables_from_sql(page_object.sqlStr)
oldStrSql=generate_pagination_sql(page_object,dsDataResource["type"])
#4.执行原始sql
result = await cls.execute_sql(dbConnent, page_object.sqlStr,"原始")
result = await cls.execute_sql(dbConnent, oldStrSql,"原始")
if 3 in role_id_list:
resultDict={
"ctrlSql": page_object.sqlStr,

2
vue-fastapi-backend/server.py

@ -35,6 +35,7 @@ from module_admin.controller.cdplb_controller import cdplbController
from module_admin.controller.sscf_controller import sscfController
from module_admin.controller.vecset_controller import vecsetController
from module_admin.controller.data_asset_controller import dataAssetController
from module_admin.controller.metadata_config_controller import metadataConfigController
from sub_applications.handle import handle_sub_applications
from utils.common_util import worship
from utils.log_util import logger
@ -103,6 +104,7 @@ controller_list = [
{'router': sscfController, 'tags': ['智能数据-短句配置']},
{'router': vecsetController, 'tags': ['智能数据-全句配置']},
{'router': dataAssetController, 'tags': ['系统管理-数据资产详情']},
{'router': metadataConfigController, 'tags': ['元数据管理-元数据配置管理']},
]
for controller in controller_list:

88
vue-fastapi-frontend/src/api/metadataConfig/metadataConfig.js

@ -0,0 +1,88 @@
import request from '@/utils/request'
// 查询元数据分类列表,带分页
export function listMetadataClas(query) {
return request({
url: '/default-api/metadataConfig/clas/list',
method: 'get',
params: query
})
}
// 查询元数据分类详情
export function getMetadataClas(clasId) {
return request({
url: '/default-api/metadataConfig/clas/' + clasId,
method: 'get'
})
}
// 新增元数据分类
export function addMetadataClas(data) {
return request({
url: '/default-api/metadataConfig/clas',
method: 'post',
data: data
})
}
// 修改元数据分类
export function updateMetadataClas(data) {
return request({
url: '/default-api/metadataConfig/clas',
method: 'put',
data: data
})
}
// 删除元数据分类(支持批量,逗号分隔)
export function delMetadataClas(clasIds) {
return request({
url: '/default-api/metadataConfig/clas/' + clasIds,
method: 'delete'
})
}
// ========================== MetadataSec 接口(新增) ==========================
// 查询数据安全配置列表,带分页
export function listMetadataSec(query) {
return request({
url: '/default-api/metadataConfig/sec/list',
method: 'get',
params: query
})
}
// 查询数据安全配置详情
export function getMetadataSec(secId) {
return request({
url: '/default-api/metadataConfig/sec/' + secId,
method: 'get'
})
}
// 新增数据安全配置
export function addMetadataSec(data) {
return request({
url: '/default-api/metadataConfig/sec',
method: 'post',
data: data
})
}
// 修改数据安全配置
export function updateMetadataSec(data) {
return request({
url: '/default-api/metadataConfig/sec',
method: 'put',
data: data
})
}
// 删除数据安全配置(支持批量,逗号分隔)
export function delMetadataSec(secIds) {
return request({
url: '/default-api/metadataConfig/sec/' + secIds,
method: 'delete'
})
}

15
vue-fastapi-frontend/src/store/modules/user.js

@ -31,13 +31,6 @@ const useUserStore = defineStore(
setToken(res.token)
this.token = res.token
resolve()
}).catch(error => {
reject(error)
})
})
},
getdsSysList(){
return new Promise((resolve, reject) => {
datasourcetree()
.then(res => {
this.dsSysList = res.rows || [] // 确保为空时不报错
@ -48,6 +41,14 @@ const useUserStore = defineStore(
this.dsSysList = [] // 请求失败也清空列表,避免残留
reject(error)
})
}).catch(error => {
reject(error)
})
})
},
getdsSysList(){
return new Promise((resolve, reject) => {
})
},
// 获取用户信息

62
vue-fastapi-frontend/src/views/dataAsset/directory/index.vue

@ -290,28 +290,51 @@
{{ currentNode.dataAstDesc }}
</el-descriptions-item>
</el-descriptions>
<el-tabs style="margin-top: 8px" v-model="activeName">
<el-tabs style="margin-top: 8px" v-model="activeName" >
<el-tab-pane label="资产字段" name="1">
<el-table :data="assetFieldData" border>
<el-table :data="assetFieldData" border height="calc(100vh - 395px)">
<el-table-column prop="fldNo" label="序号" width="60" />
<el-table-column prop="fldCnName" label="字段中文名" />
<el-table-column prop="fldEngName" label="字段英文名" />
<el-table-column prop="fldType" label="字段类型" />
<el-table-column prop="batchColClas" label="枚举" />
<el-table-column label="枚举类" width="150" align="center" prop="fldClas">
<template #default="scope">
<el-popover placement="right" width="auto" trigger="hover">
<template #reference>
<el-tag > {{ scope.row.batchColClas[0].clasName }}
</el-tag>
</template>
<div>
<div style="margin: 5px" v-for="item in scope.row.batchColClas"><el-tag v-if="item.clasEffFlag === '1'">{{item.clasName + ":" + item.clasValue}}</el-tag></div>
</div>
</el-popover>
</template>
</el-table-column>
<el-table-column prop="fldNullRate" label="有值率" />
<el-table-column prop="fldDesc" label="说明" />
</el-table>
</el-tab-pane>
<el-tab-pane label="样例数据" name="2">
<el-table :data="metaSecurityData" border>
<el-table
:data="metaSecurityData"
border
height="calc(100vh - 395px)"
:row-style="() => ({ height: '50px', overflow: 'hidden' })"
:cell-style="() => ({ padding: '0', lineHeight: '40px', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' })"
>
<el-table-column
v-for="(column, index) in tablesRowCol"
min-width="180"
:key="index"
min-width="180"
:prop="column.prop"
:label="column.label || column.prop"
show-overflow-tooltip
/>
</el-table>
</el-table>
</el-tab-pane>
<el-tab-pane label="常见问题" name="3">
<div class="faq">
@ -390,6 +413,7 @@ const defaultProps = {
}
const directoryTree = ref([])
const currentNode = ref({})
const currentColumnData = ref({});
const directoryTableData = ref([])
const tableHeaderLabel = computed(() => {
@ -512,27 +536,21 @@ const handleNodeClick = async (node) => {
await setHtmlContent(node)
} else {
faq.value = node.dataAstFaq
const fides =await getAssetFieldTable(node.astNo)
assetFieldData.value = fides.data.columnList || []
tablesRowCol.value = assetFieldData.value.map((item) => ({
prop: item.fldEngName,
label: item.fldCnName,
}))
getMetaSecurityData({
dataAstSrc: node.dataAstSrc,
dataAstEngName: node.dataAstEngName,
})
.then(({ data }) => {
metaSecurityData.value = data.data
tablesRowCol.value = data.tablesRowCol
.split(',')
.map((i) => ({ prop: i, label: '' }))
return getAssetFieldTable(node.astNo)
})
.then(({ data }) => {
assetFieldData.value = data.columnList || []
tablesRowCol.value = tablesRowCol.value.map((i) => {
const item = assetFieldData.value.find((j) => j.fldEngName === i.prop)
if (item) {
i.label = item.fldCnName
}
return i
})
})
}
}
@ -734,7 +752,9 @@ const handleIframeLoad = () => {
.faq {
white-space: pre-wrap;
}
.full-height-tabs {
height: calc(100vh - 320px);
}
.html-box {
:deep(.el-card__body) {
overflow: auto;

301
vue-fastapi-frontend/src/views/metadataConfig/clas/index.vue

@ -0,0 +1,301 @@
<template>
<div class="app-container">
<el-row :gutter="10" class="mb8">
<el-form :inline="true" :model="queryForm" >
<el-form-item label="标签一级分类">
<el-input v-model="queryForm.clasPriClas" placeholder="请输入标签一级分类" clearable />
</el-form-item>
<el-form-item label="标签名称">
<el-input v-model="queryForm.clasName" placeholder="请输入标签名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="openAddDialog"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="selectedRows.length !== 1"
@click="openEditDialog(selectedRows[0])"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="selectedRows.length === 0"
@click="deleteSelected"
>删除</el-button>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="configList"
@selection-change="handleSelectionChange"
style="width: 100%"
border
stripe
>
<el-table-column type="selection" width="55" />
<el-table-column prop="clasOnum" label="标签序号" width="200" />
<el-table-column prop="clasPriClas" label="标签一级分类" width="150" />
<el-table-column prop="clasScdClas" label="标签二级分类" width="150" />
<el-table-column prop="clasThreClas" label="标签三级分类" width="150" />
<el-table-column prop="clasName" label="标签名称" width="200" />
<el-table-column prop="clasTmpl" label="标签模版" width="200" />
<el-table-column prop="clasEffFlag" label="有效标志" width="100">
<template #default="{ row }">
<el-tag :type="row.clasEffFlag === '1' ? 'success' : 'info'">
{{ row.clasEffFlag === '1' ? '有效' : '无效' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="recSubmPrsn" label="提交人" width="120" />
<el-table-column prop="updTime" label="更新时间" width="180" />
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryForm.pageNum"
v-model:limit="queryForm.pageSize"
@pagination="getList"
/>
<el-dialog
:title="title"
v-model="open"
width="500px"
append-to-body
:before-close="handleClose"
>
<el-form
ref="clasFormRef"
:model="form"
:rules="rules"
label-width="120px"
size="small"
>
<el-form-item label="标签序号" prop="clasPriClas">
<el-input v-model="form.clasOnum" autocomplete="off" type="number" :disabled="title != '新增标签信息'"/>
</el-form-item>
<el-form-item label="标签一级分类" prop="clasPriClas">
<el-input v-model="form.clasPriClas" autocomplete="off" />
</el-form-item>
<el-form-item label="标签二级分类" prop="clasScdClas">
<el-input v-model="form.clasScdClas" autocomplete="off" />
</el-form-item>
<el-form-item label="标签三级分类" prop="clasThreClas">
<el-input v-model="form.clasThreClas" autocomplete="off" />
</el-form-item>
<el-form-item label="标签名称" prop="clasName">
<el-input v-model="form.clasName" autocomplete="off" />
</el-form-item>
<el-form-item label="标签模版" prop="clasTmpl">
<el-input v-model="form.clasTmpl" autocomplete="off" />
</el-form-item>
<el-form-item label="有效标志" prop="clasEffFlag">
<el-select v-model="form.clasEffFlag" placeholder="请选择有效标志">
<el-option label="有效" value="1" />
<el-option label="无效" value="0" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="open = false">取消</el-button>
<el-button type="primary" @click="submitForm">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import {
listMetadataClas,
addMetadataClas,
updateMetadataClas,
delMetadataClas
} from '@/api/metadataConfig/metadataConfig'
const queryForm = reactive({
clasPriClas: '',
clasName: '',
pageNum: 1,
pageSize: 10
})
const configList = ref([])
const total = ref(0) //
const loading = ref(false)
const open = ref(false)
const title = ref('')
const clasFormRef = ref(null)
const form = reactive({
clasOnum: null,
clasPriClas: '',
clasScdClas: '',
clasThreClas: '',
clasName: '',
clasTmpl: '',
clasEffFlag: '',
recSubmPrsn: ''
})
const rules = {
clasPriClas: [{ required: true, message: '请输入标签一级分类', trigger: 'blur' }],
clasOnum: [{ required: true, message: '请输入标签序号', trigger: 'blur' }],
clasName: [{ required: true, message: '请输入标签名称', trigger: 'blur' }],
clasEffFlag: [{ required: true, message: '请选择有效标志', trigger: 'change' }]
}
const selectedRows = ref([])
function handleSelectionChange(val) {
selectedRows.value = val
}
async function getList() {
loading.value = true
try {
// page pageSize
const res = await listMetadataClas(queryForm)
configList.value = res.rows || []
total.value = res.total || 0
} catch (error) {
ElMessage.error('获取列表失败,请重试')
} finally {
loading.value = false
}
}
function resetQuery() {
queryForm.clasPriClas = ''
queryForm.clasName = ''
queryForm.pageNum = 1
getList()
}
function handleSearch() {
queryForm.pageNum = 1
getList()
}
function handlePageChange(newPage) {
queryForm.pageNum = newPage
getList()
}
function openAddDialog() {
title.value = '新增标签信息'
Object.assign(form, {
clasOnum: null,
clasPriClas: '',
clasScdClas: '',
clasThreClas: '',
clasName: '',
clasTmpl: '',
clasEffFlag: '',
recSubmPrsn: ''
})
open.value = true
}
function openEditDialog(row) {
if (!row) {
ElMessage.warning('请选择一条记录进行编辑')
return
}
title.value = '编辑标签信息'
Object.assign(form, row)
open.value = true
}
function submitForm() {
clasFormRef.value.validate(async (valid) => {
if (!valid) return
const submitData = { ...form }
delete submitData.recSubmPrsn
try {
if (title.value.includes('新增')) {
await addMetadataClas(submitData)
ElMessage.success('新增成功')
} else {
await updateMetadataClas(submitData)
ElMessage.success('编辑成功')
}
open.value = false
getList()
} catch (error) {
ElMessage.error('操作失败,请重试')
}
})
}
function deleteRow(id) {
ElMessageBox.confirm('确定删除该标签信息吗?', '提示', { type: 'warning' })
.then(async () => {
try {
await delMetadataClas(id)
ElMessage.success('删除成功')
getList()
} catch (error) {
ElMessage.error('删除失败,请重试')
}
})
.catch(() => {})
}
//
function deleteSelected() {
if (selectedRows.value.length === 0) {
ElMessage.warning('请至少选择一条记录删除')
return
}
ElMessageBox.confirm(`确定删除选中的 ${selectedRows.value.length} 条标签信息吗?`, '提示', { type: 'warning' })
.then(async () => {
try {
for (const row of selectedRows.value) {
await delMetadataClas(row.clasOnum)
}
ElMessage.success('删除成功')
getList()
} catch (error) {
ElMessage.error('删除失败,请重试')
}
})
.catch(() => {})
}
function handleClose(done) {
clasFormRef.value.resetFields()
done()
}
onMounted(() => {
getList()
})
</script>

293
vue-fastapi-frontend/src/views/metadataConfig/sec/index.vue

@ -0,0 +1,293 @@
<template>
<div class="app-container">
<el-row :gutter="10" class="mb8">
<el-form :inline="true" :model="queryForm" >
<el-form-item label="唯一编号">
<el-input v-model="queryForm.onum" placeholder="请输入唯一编号" clearable />
</el-form-item>
<el-form-item label="等级名称">
<el-input v-model="queryForm.secLevelName" placeholder="请输入等级名称" clearable />
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleSearch">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-row>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button
type="primary"
plain
icon="Plus"
@click="openAddDialog"
>新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="success"
plain
icon="Edit"
:disabled="selectedRows.length !== 1"
@click="openEditDialog(selectedRows[0])"
>修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button
type="danger"
plain
icon="Delete"
:disabled="selectedRows.length === 0"
@click="deleteSelected"
>删除</el-button>
</el-col>
</el-row>
<el-table
v-loading="loading"
:data="secList"
@selection-change="handleSelectionChange"
style="width: 100%"
border
stripe
>
<el-table-column type="selection" width="55" />
<el-table-column prop="secLevelSummary" label="等级简称" />
<el-table-column prop="secLevelName" label="等级名称" />
<el-table-column prop="secLevelDesc" label="等级说明"/>
<el-table-column prop="secEffFlag" label="有效标志">
<template #default="{ row }">
<el-tag :type="row.secEffFlag === '1' ? 'success' : 'info'">
{{ row.secEffFlag === '1' ? '有效' : '无效' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="updTime" label="更新时间" width="180" />
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryForm.pageNum"
v-model:limit="queryForm.pageSize"
@pagination="getList"
/>
<el-dialog
:title="title"
v-model="open"
width="550px"
append-to-body
:before-close="handleClose"
>
<el-form
ref="secFormRef"
:model="form"
:rules="rules"
label-width="120px"
size="small"
>
<el-form-item label="等级简称" prop="secLevelSummary">
<el-input v-model="form.secLevelSummary" autocomplete="off" />
</el-form-item>
<el-form-item label="等级名称" prop="secLevelName">
<el-input v-model="form.secLevelName" autocomplete="off" />
</el-form-item>
<el-form-item label="等级说明" prop="secLevelDesc">
<el-input type="textarea" v-model="form.secLevelDesc" autocomplete="off" />
</el-form-item>
<el-form-item label="有效标志" prop="secEffFlag">
<el-select v-model="form.secEffFlag" placeholder="请选择有效标志">
<el-option label="有效" value="1" />
<el-option label="无效" value="0" />
</el-select>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="open = false">取消</el-button>
<el-button type="primary" @click="submitForm">保存</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import {
listMetadataSec,
addMetadataSec,
updateMetadataSec,
delMetadataSec
} from '@/api/metadataConfig/metadataConfig'
const queryForm = reactive({
onum: '',
secLevelName: '',
pageNum: 1,
pageSize: 10
})
const secList = ref([])
const total = ref(0)
const loading = ref(false)
const open = ref(false)
const title = ref('')
const secFormRef = ref(null)
const form = reactive({
onum: '',
secEffFlag: '',
recSubmPrsn: '',
updTime: '',
secLevelName: '',
secLevelDesc: '',
secLevelSummary: ''
})
const rules = {
secEffFlag: [{ required: true, message: '请选择有效标志', trigger: 'change' }],
secLevelName: [{ required: true, message: '请输入等级名称', trigger: 'blur' }]
}
const selectedRows = ref([])
function handleSelectionChange(val) {
selectedRows.value = val
}
async function getList() {
loading.value = true
try {
const res = await listMetadataSec(queryForm)
secList.value = res.rows || []
total.value = res.total || 0
} catch (error) {
ElMessage.error('获取列表失败,请重试')
} finally {
loading.value = false
}
}
function resetQuery() {
queryForm.onum = ''
queryForm.secLevelName = ''
queryForm.pageNum = 1
getList()
}
function handleSearch() {
queryForm.pageNum = 1
getList()
}
function openAddDialog() {
title.value = '新增等级信息'
Object.assign(form, {
onum: '',
secEffFlag: '',
recSubmPrsn: '',
updTime: '',
secLevelName: '',
secLevelDesc: '',
secLevelSummary: ''
})
open.value = true
}
function openEditDialog(row) {
if (!row) {
ElMessage.warning('请选择一条记录进行编辑')
return
}
title.value = '编辑等级信息'
Object.assign(form, row)
open.value = true
}
function submitForm() {
secFormRef.value.validate(async (valid) => {
if (!valid) return
const submitData = { ...form }
delete submitData.updTime // updTime
try {
if (title.value.includes('新增')) {
await addMetadataSec(submitData)
ElMessage.success('新增成功')
} else {
await updateMetadataSec(submitData)
ElMessage.success('编辑成功')
}
open.value = false
getList()
} catch (error) {
ElMessage.error('操作失败,请重试')
}
})
}
function deleteRow(onum) {
ElMessageBox.confirm('确定删除该等级信息吗?', '提示', { type: 'warning' })
.then(async () => {
try {
await delMetadataSec(onum)
ElMessage.success('删除成功')
getList()
} catch (error) {
ElMessage.error('删除失败,请重试')
}
})
.catch(() => {})
}
function deleteSelected() {
if (selectedRows.value.length === 0) {
ElMessage.warning('请至少选择一条记录删除')
return
}
ElMessageBox.confirm(`确定删除选中的 ${selectedRows.value.length} 条等级信息吗?`, '提示', { type: 'warning' })
.then(async () => {
try {
for (const row of selectedRows.value) {
await delMetadataSec(row.onum)
}
ElMessage.success('删除成功')
getList()
} catch (error) {
ElMessage.error('删除失败,请重试')
}
})
.catch(() => {})
}
function handleClose(done) {
secFormRef.value.resetFields()
done()
}
onMounted(() => {
getList()
})
</script>
<style scoped>
.app-container {
padding: 20px;
}
.mb8 {
margin-bottom: 8px;
}
</style>
Loading…
Cancel
Save