Browse Source

安全等级配置

master
si@aidatagov.com 1 week ago
parent
commit
71eff27715
  1. 67
      vue-fastapi-backend/module_admin/controller/metadata_config_controller.py
  2. 36
      vue-fastapi-backend/module_admin/dao/metadata_config_dao.py
  3. 13
      vue-fastapi-backend/module_admin/entity/do/metadata_config_do.py
  4. 45
      vue-fastapi-backend/module_admin/entity/vo/metadata_config_vo.py
  5. 76
      vue-fastapi-backend/module_admin/service/metadata_config_service.py
  6. 44
      vue-fastapi-frontend/src/api/metadataConfig/metadataConfig.js
  7. 293
      vue-fastapi-frontend/src/views/metadataConfig/sec/index.vue

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

@ -2,7 +2,7 @@ from datetime import datetime
from fastapi import APIRouter, Depends, Request, Form from fastapi import APIRouter, Depends, Request, Form
from pydantic_validation_decorator import ValidateFields from pydantic_validation_decorator import ValidateFields
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel,MetadataSecModel,MetadataSecPageQueryModel
from module_admin.service.metadata_config_service import MetadataConfigService from module_admin.service.metadata_config_service import MetadataConfigService
from config.get_db import get_db from config.get_db import get_db
from utils.response_util import ResponseUtil from utils.response_util import ResponseUtil
@ -78,3 +78,68 @@ async def get_metadata_clas_detail(
result = await MetadataConfigService.get_metadata_clas_detail_services(query_db, clas_id) result = await MetadataConfigService.get_metadata_clas_detail_services(query_db, clas_id)
logger.info(f"获取元数据分类ID={clas_id}详情成功") logger.info(f"获取元数据分类ID={clas_id}详情成功")
return ResponseUtil.success(data=result) 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)

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

@ -2,6 +2,7 @@ from datetime import datetime, time
from sqlalchemy import delete, select, update from sqlalchemy import delete, select, update
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.entity.do.meta_do import MetadataClas # ORM 类 from module_admin.entity.do.meta_do import MetadataClas # ORM 类
from module_admin.entity.do.metadata_config_do import MetadataSec # ORM 类
class MetadataConfigDao: class MetadataConfigDao:
@ -78,3 +79,38 @@ class MetadataConfigDao:
删除标签信息支持批量 删除标签信息支持批量
""" """
await db.execute(delete(MetadataClas).where(MetadataClas.clas_onum.in_(clas_onum_list))) 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)))

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

@ -18,3 +18,16 @@ from config.database import Base
# clas_eff_flag = Column(String(1), default=None, comment='标签有效标志') # clas_eff_flag = Column(String(1), default=None, comment='标签有效标志')
# rec_subm_prsn = Column(String(64), 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='更新时间') # 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='等级简介')

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

@ -59,3 +59,48 @@ class DeleteMetadataClasModel(BaseModel):
clas_onums: str = Field(description='需要删除的标签主键(多个用逗号分隔)') 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='每页记录数')

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

@ -1,10 +1,10 @@
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from module_admin.dao.metadata_config_dao import MetadataConfigDao from module_admin.dao.metadata_config_dao import MetadataConfigDao
from module_admin.entity.vo.common_vo import CrudResponseModel from module_admin.entity.vo.common_vo import CrudResponseModel
from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel from module_admin.entity.vo.metadata_config_vo import MetadataClasModel, MetadataClasPageQueryModel,MetadataSecModel,MetadataSecPageQueryModel
from utils.common_util import CamelCaseUtil from utils.common_util import CamelCaseUtil
from exceptions.exception import ServiceException from exceptions.exception import ServiceException
import uuid
class MetadataConfigService: class MetadataConfigService:
""" """
@ -88,3 +88,75 @@ class MetadataConfigService:
return MetadataClasModel(**CamelCaseUtil.transform_result(result)) return MetadataClasModel(**CamelCaseUtil.transform_result(result))
else: else:
return MetadataClasModel(**dict()) 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())

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

@ -42,3 +42,47 @@ export function delMetadataClas(clasIds) {
method: 'delete' 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'
})
}

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