Commit 2b60e6ce by 周海峰

项目加密设置页面

parent 755912ad
......@@ -889,6 +889,93 @@ export function queryExtendColumnSize(data) {
})
}
/**
* 查询加密类型
* @param {*} data
* @returns {"code":"200","msg":"","totalCount":0,"flag":true,"data":["jdbc","webhdfs"]}
*/
export function enctypes(data) {
return request({
url: '/core/tablerule/enctypes',
method: 'post',
data: data
})
}
/**
* 查询后缀
* @param {*} data
* @returns
* {
* "code": "POP_00014",
* "msg": "成功。",
* "totalCount": 0,
* "flag": true,
* "data": {
* "cipherSuffix": "_cipher",
* "initialSuffix": "_initial",
* "copySuffix": "_copy"
* }
* }
*/
export function queryPostfix(data) {
return request({
url: '/core/encryption/queryPostfix',
method: 'post',
data: data
})
}
/**
* 查询版本
* @param {*} data id
* @returns
* {
* "code": "POP_00014",
* "msg": "成功。",
* "totalCount": 0,
* "flag": true,
* "data": [
* {
* "value": "TaskVersion",
* "text": "任务版本",
* "flag": null,
* "filePath": null,
* "id": null,
* "dbType": null,
* "schmeid": null,
* "dataSystemId": null,
* "tid": null
* },
* {
* "value": "null",
* "text": "无版本",
* "flag": null,
* "filePath": null,
* "id": null,
* "dbType": null,
* "schmeid": null,
* "dataSystemId": null,
* "tid": null
* }
* ]
* }
*/
export function queryversion(data) {
return request({
url: '/core/fieldscopedata/queryversion',
method: 'post',
data: data
})
}
//=========== 点击字段的设置===========开始
/**
......@@ -1037,9 +1124,51 @@ export function encryptionQuery(data) {
return request({
url: '/core/encryption/query',
method: 'get',
data: data
query: data
})
}
//=========== 点击字段的设置===========结束
/**
* 删除多余列(表字段)
* @param {*} data
* @returns
*/
export function delTableColumn(data) {
return request({
url: '/switchfield/delTableColumn',
method: 'POST',
data: data
})
}
/**
* 保存加密配置
* @param {*} data
* {
* datasystemid: '',
* projectId: '',
* map: {
* ry#|#sys_user#|#dept_id: {
* columnType: "BIGINT",
* describe_info: "11",
* encdigit: "0",
* encryptionSecretKeyId: "",
* flag: "0",
* note: "部门ID",
* realitycolumnsize: "19",
* twoindex: "0"
* }
* }
* @returns
*/
export function save(data) {
return request({
url: '/core/encryptionconfig/save',
method: 'POST',
data: data
})
}
<script setup name="Classification">
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted } from 'vue'
import { ElMessageBox, ElMessage } from 'element-plus'
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted, watch } from 'vue'
import TreeFilter from './modules/TreeFilter.vue'
import BasicInfoTab from './modules/BasicInfoTab.vue'
import TableInfoTab from './modules/TableInfoTab.vue'
......@@ -9,68 +10,22 @@ import { changeRoute } from '@/utils/switchRoute'
import { useRouter } from 'vue-router'
import useAppStore from '@/store/modules/app'
import usePermissionStore from '@/store/modules/permission'
const appStore = useAppStore()
const permissionStore = usePermissionStore()
const router = useRouter()
const { proxy } = getCurrentInstance()
import { query, getClassifyEnable, getGlobalOriginalConfig, changeGlobalOriginalConfig, queryDatasystemInfo,
queryShemas, queryTables, querytableInfo, getfield,
queryOriginalList, queryEncryptionList
} from '@/api/classification/classification.js'
const route = useRoute()
const projectId = ref('')
onMounted(()=>{
projectId.value =proxy.$route.query.projectId
console.log('projectId',projectId.value)
})
// const props = defineProps({
// projectId: String, // 主键
// })
// 树形数据
const treeData = ref([
{
id: 'system',
label: '若依配测系统',
type: 'system',
children: [
{
id: 'database',
label: 'ry',
type: 'database',
children: [
{
id: 'tables',
label: '表',
type: 'category',
children: [
{ id: 'gen_table', label: 'gen_table', type: 'table' },
{ id: 'gen_table_column', label: 'gen_table_column', type: 'table' },
{ id: 'sys_config', label: 'sys_config', type: 'table' },
{ id: 'sys_dept', label: 'sys_dept', type: 'table' },
{ id: 'sys_dict_data', label: 'sys_dict_data', type: 'table' },
{ id: 'sys_dict_type', label: 'sys_dict_type', type: 'table' },
{ id: 'sys_job', label: 'sys_job', type: 'table' },
{ id: 'sys_job_log', label: 'sys_job_log', type: 'table' },
{ id: 'sys_logininfor', label: 'sys_logininfor', type: 'table' },
{ id: 'sys_menu', label: 'sys_menu', type: 'table' },
{ id: 'sys_notice', label: 'sys_notice', type: 'table' },
{ id: 'sys_oper_log', label: 'sys_oper_log', type: 'table' },
{ id: 'sys_post', label: 'sys_post', type: 'table' },
{ id: 'sys_role', label: 'sys_role', type: 'table' },
{ id: 'sys_role_dept', label: 'sys_role_dept', type: 'table' },
{ id: 'sys_role_menu', label: 'sys_role_menu', type: 'table' },
{ id: 'sys_user', label: 'sys_user', type: 'table' },
{ id: 'sys_user_online', label: 'sys_user_online', type: 'table' },
{ id: 'sys_user_post', label: 'sys_user_post', type: 'table' },
{ id: 'sys_user_role', label: 'sys_user_role', type: 'table' }
]
}
]
}
]
}
])
const treeData = ref([])
// 基本信息数据(当前选中的数据源)
const basicInfoData = ref({})
// 当前激活的Tab
const activeTab = ref('basic')
// 当前选中的节点数据
const currentNodeData = ref(null)
const currentNodeLevel = computed(() => {
if (!currentNodeData.value) return 0
if (!currentNodeData.value) return 1
if (currentNodeData.value.type === 'system') return 1
if (currentNodeData.value.type === 'database') return 2
if (currentNodeData.value.type === 'category') return 3
......@@ -78,32 +33,204 @@ const currentNodeLevel = computed(() => {
return 0
})
// 是否启用解密插件
const enableDecryptionPlugin = ref(false)
// 当前表结构数据 (匹配图片中的gen_table结构)
const currentTableStructure = ref([])
// 当前表字段加密配置
const originalList = ref([])
// 当前激活的Tab
const activeTab = ref('basic')
// 监听 currentNodeLevel 和 currentNodeData,一级节点时自动查详情
watch([currentNodeLevel, currentNodeData, activeTab], async ([level, node, tab]) => {
if (level === 1 && node && tab === 'basic') {
const res = await queryDatasystemInfo({ dataSystemId: node.tid, projectId: projectId.value })
if (res && res.data) {
// 你可以将结果赋值到 basicInfoData 或其他变量
basicInfoData.value = { ...basicInfoData.value, ...res.data }
}
}
// 当前表结构数据 (匹配图片中的gen_table结构)
const currentTableStructure = ref([
{ pk: '', fieldName: 'business_name', comment: '生成业务名', fieldType: 'VARCHAR', length: '30', precision: '', algorithm: '' },
{ pk: '', fieldName: 'business_name_...', comment: '', fieldType: 'TEXT', length: '65535', precision: '', algorithm: '' },
{ pk: '', fieldName: 'class_name', comment: '实体类名称', fieldType: 'VARCHAR', length: '100', precision: '', algorithm: '' },
{ pk: '', fieldName: 'create_by', comment: '创建者', fieldType: 'VARCHAR', length: '64', precision: '', algorithm: '' },
{ pk: '', fieldName: 'create_time', comment: '创建时间', fieldType: 'DATETIME', length: '19', precision: '', algorithm: '' },
{ pk: '', fieldName: 'function_author', comment: '生成功能作者', fieldType: 'VARCHAR', length: '50', precision: '', algorithm: '' },
{ pk: '', fieldName: 'function_name', comment: '生成功能名', fieldType: 'VARCHAR', length: '50', precision: '', algorithm: '' },
{ pk: '', fieldName: 'gen_path', comment: '生成路径(不填...', fieldType: 'VARCHAR', length: '200', precision: '', algorithm: '' },
{ pk: '', fieldName: 'gen_type', comment: '生成代码方式(0...', fieldType: 'CHAR', length: '1', precision: '', algorithm: '' },
{ pk: '', fieldName: 'module_name', comment: '生成模块名', fieldType: 'VARCHAR', length: '30', precision: '', algorithm: '' }
])
// 查询表基本信息
if (level === 4 && node && tab === 'basic') {
console.log('查询表基本信息', node)
const res = await querytableInfo({
tableName: node.label,
dataSystemId: node.parent?.parent?.tid,
schema: node.parent?.parent?.label,
flag: '1',
projectId: projectId.value
})
if (res && res.data) {
// 你可以将结果赋值到 basicInfoData 或其他变量
basicInfoData.value = {...res.data }
}
}
// 查询表字段信息
if (level === 4 && node && tab === 'structure') {
console.log('查询表字段信息', node)
const res = await getfield({
tablename: node.label,
datasystemid: node.parent?.parent?.tid,
schema: node.parent?.parent?.label,
taskid: ''
})
if (res && res.data) {
// 你可以将结果赋值到 basicInfoData 或其他变量
currentTableStructure.value = res.data || []
}
}
//查询字段加密配置
if (level === 4 && node && tab === 'encryption') {
console.log('查询字段加密配置', node)
// 查询字段原始值配置&字段加密配置
const [originalListRes, encryptionListRes] = await Promise.all([
queryOriginalList({
table_name: node.label,
datasystem_id: node.parent?.parent?.tid,
schema: node.parent?.parent?.label,
projectId: projectId.value
}),
queryEncryptionList({
table_name: node.label,
datasystem_id: node.parent?.parent?.tid,
schema: node.parent?.parent?.label,
projectId: projectId.value
})
])
console.log('encryptionListRes', encryptionListRes)
console.log('originalListRes', originalListRes)
if (originalListRes && originalListRes.data) {
// 处理字段加密配置
originalListRes.data.forEach(item => {
const encryptionItem = encryptionListRes.data.find(en => en.fieldName === item.columnname)
if (encryptionItem) {
item.maskingruleid = encryptionItem.encryptionIdTrue
item.maskingrulename = encryptionItem.encryptionTypeName
item.secretkeyId = encryptionItem.secretKey
item.secretkeyName = encryptionItem.encryptionTypeValue
item.flag = encryptionItem.flag
}
})
// 你可以将结果赋值到 basicInfoData 或其他变量
originalList.value = originalListRes.data || []
}
}
})
onMounted(async () => {
projectId.value = route.query.projectId || 'df345570-d044-47b3-a2c6-0ff265f89b80'
if (projectId.value) {
// 1. 查询数据源列表
const res = await query({ project_id: projectId.value })
if (res && res.data) {
treeData.value = res.data.map(item => ({
...item,
label: item.sysname,
type: 'system',
children: [
]
}))
// 赋值触发监听,默认查询第一个数据源的基本信息
currentNodeData.value = treeData.value[0]
}
// 查询解密插件配置
const configRes = await getGlobalOriginalConfig({ projectId: projectId.value })
console.log('解密插件配置', configRes)
if (configRes) {
enableDecryptionPlugin.value = configRes.data === 1
}
}
})
// 树节点点击处理
const handleNodeClick = (data) => {
const handleNodeClick = async (data) => {
currentNodeData.value = data
// 2. 点击一层系统数据,查 schemas
if (data.type === 'system') {
activeTab.value = 'basic'
const res = await queryShemas({
dataSystemId: data.tid,
dataType: data.dbtype,
projectid: projectId.value
})
if (res && res.data) {
data.children = res.data.map(schema => ({
id: uuid(),
...schema,
type: 'database',
label: schema.text,
parent: data,
children: [
{
id: uuid(),
label: '表',
type: 'category',
parent: {
...schema,
type: 'database',
label: schema.text,
parent: data,
tid: data.tid,
dbservername: schema.text
},
children: []
}
]
}))
treeData.value = [...treeData.value] // 触发视图更新
}
}
// 3. 点击三层 category,查表
if (data.type === 'category' && data.parent) {
const parentDb = data.parent
const res = await queryTables({
dataSystemId: parentDb.tid,
schema: parentDb.dbservername
})
if (res && res.data) {
data.children = res.data.map(table => ({
...table,
label: table.showName,
type: 'table',
parent: data
}))
treeData.value = [...treeData.value]
}
}
}
// 是否启用解密插件
const enableDecryptionPlugin = ref(true)
// 解密插件变更处理
const handleDecryptChange = async (val) => {
try {
const res = await changeGlobalOriginalConfig({ projectId: projectId.value, status: val ? '1' : '0' })
if (!res || res.code !== 'POP_00014' || !res.flag) {
// 如果修改失败,回退到之前的值
enableDecryptionPlugin.value = !val
ElMessageBox.alert('修改解密插件配置失败,请重试', '错误', {
confirmButtonText: '确定',
type: 'error'
})
}
} catch (e) {
// 如果修改失败,回退到之前的值
enableDecryptionPlugin.value = !val
// 可根据需要添加错误提示
ElMessageBox.alert('修改解密插件配置失败,请重试', '错误', {
confirmButtonText: '确定',
type: 'error'
})
}
}
// 批量加密
const handleBatchEncrypt = () => {
console.log('批量加密', currentNodeData.value)
......@@ -119,24 +246,45 @@ const handleDeleteColumns = () => {
console.log('删除多余列', currentNodeData.value)
}
const handleSave = () => {
console.log('保存更改', currentNodeData.value)
}
// 编辑字段
const handleEditField = (field) => {
console.log('编辑字段', field)
}
const openDecrypt = ref(false)
function pageProjectManage() {
function pageProjectManage() {
changeRoute()
router.push({
path: '/project/Project'
})
}
defineExpose({
// handleRedInk,
// handleVoid
})
const getBreadcrumb = () => {
const result = []
let node = currentNodeData.value
while (node) {
result.unshift({ label: node.label })
node = node.parent
}
// 如果没有选中节点,默认显示系统
if (result.length === 0) {
result.push({ label: treeData.value.length > 0 ? treeData.value[0].label : '数据源' })
}
return result
}
// 生成唯一标识符
function uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
</script>
<template>
......@@ -145,34 +293,23 @@ defineExpose({
<template #title>
返回项目管理
</template>
</PageTitle>
<div class="app-container__body">
<div class="flex-container content-container">
<div class="left">
<el-card class="image-card tree-container">
<TreeFilter :tree-data="treeData" @node-click="handleNodeClick"/>
</el-card>
</div>
<div class="right flex1">
<el-card class="image-card">
<div class="header-section">
<div class="breadcrumb flex-container justify-between align-center">
<el-breadcrumb separator="/">
<el-breadcrumb-item>若依配测系统</el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 2">ry</el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 3"></el-breadcrumb-item>
<el-breadcrumb-item v-if="currentNodeLevel >= 4">{{ currentNodeData?.label }}</el-breadcrumb-item>
<el-breadcrumb-item v-for="(item, $index) in getBreadcrumb()" :key="$index">
{{ item.label }}
</el-breadcrumb-item>
</el-breadcrumb>
<el-checkbox v-model="openDecrypt">是否启用解密插件</el-checkbox>
</div>
<div class="radio-group" v-if="currentNodeLevel === 4">
<el-radio-group v-model="enableDecryptionPlugin">
<el-radio :label="true">启用解密插件</el-radio>
<el-radio :label="false">不启用解密插件</el-radio>
</el-radio-group>
<el-checkbox v-model="enableDecryptionPlugin" @change="handleDecryptChange">是否启用解密插件</el-checkbox>
</div>
</div>
......@@ -182,15 +319,15 @@ defineExpose({
<!-- 基本信息Tab -->
<el-tab-pane label="基本信息" name="basic">
<BasicInfoTab
:node-data="currentNodeData"
v-if="activeTab === 'basic' && currentNodeLevel === 1"
:node-data="basicInfoData"
v-if="activeTab === 'basic' && [1,2,3].includes(currentNodeLevel)"
/>
<!-- 表信息Tab -->
<TableInfoTab
:node-data="currentNodeData"
:node-data="basicInfoData"
v-if="activeTab === 'basic' && currentNodeLevel === 4"
/>
</el-tab-pane>
<!-- 数据结构Tab (仅4级节点显示) -->
......@@ -204,10 +341,11 @@ defineExpose({
<!-- 字段加密配置Tab (仅4级节点显示) -->
<el-tab-pane label="字段加密配置" name="encryption" v-if="currentNodeLevel === 4">
<EncryptionTab
:table-data="currentTableStructure"
:table-data="originalList"
@batch-encrypt="handleBatchEncrypt"
@batch-decrypt="handleBatchDecrypt"
@delete-columns="handleDeleteColumns"
@save-changes="handleSave"
@edit-field="handleEditField"
v-if="activeTab === 'encryption'"
/>
......@@ -241,6 +379,7 @@ defineExpose({
.left {
.tree-container {
width: 300px;
overflow-y: auto; // 内容超出滚动
}
}
.right {
......
<template>
<div class="basic-info-tab">
<el-descriptions
title="系统基本信息"
title=""
border
:column="1"
size="medium"
>
<el-descriptions-item label="项目">若依配测系统</el-descriptions-item>
<el-descriptions-item label="数据源">若依配测系统</el-descriptions-item>
<el-descriptions-item label="数据源类型">MYSQL</el-descriptions-item>
<el-descriptions-item label="IP">172.19.1.166</el-descriptions-item>
<el-descriptions-item label="管理的SCHEMA">ry</el-descriptions-item>
<el-descriptions-item label="项目">{{ nodeInfo.projectName || ''}}</el-descriptions-item>
<el-descriptions-item label="数据源">{{ nodeInfo.datasystemName || ''}}</el-descriptions-item>
<el-descriptions-item label="数据源类型">{{ nodeInfo.dbType || ''}}</el-descriptions-item>
<el-descriptions-item label="IP">{{ nodeInfo.ip || ''}}</el-descriptions-item>
<el-descriptions-item label="管理的SCHEMA">{{ nodeInfo.schema || ''}}</el-descriptions-item>
<el-descriptions-item label="字段数">{{ nodeInfo.totalFiledNum || ''}}</el-descriptions-item>
<el-descriptions-item label="加密表数量">{{ nodeInfo.encryptTableCount || ''}}</el-descriptions-item>
<el-descriptions-item label="加密字段数量">{{ nodeInfo.encryptFiledCount || ''}}</el-descriptions-item>
<el-descriptions-item label="未加密字段数量">{{ nodeInfo.unencryptTableCount || ''}}</el-descriptions-item>
<el-descriptions-item label="未加密字段数量">{{ nodeInfo.unencryptFiledCount || ''}}</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
// 可以留空,因为数据是静态的
import { computed } from 'vue'
const props = defineProps({
nodeData: {
type: Object,
default: () => ({})
}
})
// 可根据不同级别节点展示不同内容
const nodeType = computed(() => props.nodeData?.type)
const nodeInfo = computed(() => props.nodeData || {})
</script>
<style scoped>
......
......@@ -5,51 +5,68 @@
<el-form :inline="true" :model="filterForm" class="filter-form">
<el-form-item label="字段名过滤:">
<el-input
v-model="filterForm.fieldName"
v-model="filterForm.columnname"
placeholder="字段名模糊搜索"
clearable
style="width: 200px;"
/>
</el-form-item>
<el-form-item label="状态:">
<el-select style="width: 200px;" v-model="filterForm.status" placeholder="全部" clearable>
<el-option label="已加密" value="encrypted" />
<el-option label="未加密" value="unencrypted" />
<el-select style="width: 200px;" v-model="filterForm.flag" placeholder="全部" clearable>
<el-option label="全部" value="" />
<el-option v-for="item in encryptFlag" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item>
<!-- <el-form-item>
<el-button type="primary" @click="handleSearch">搜索</el-button>
</el-form-item>
</el-form-item> -->
</el-form>
</div>
<!-- 表格区域 -->
<div class="table-wrapper" style="position:relative;">
<el-table
:data="filteredTableData"
border
style="width: 100%; margin-top: 15px;"
max-height="500px"
:row-class-name="tableRowClassName"
>
<!-- 左浮动列 -->
<el-table-column prop="pk" label="主键" width="60" align="left" fixed />
<el-table-column prop="fieldName" label="字段名" width="150" align="left" fixed/>
<el-table-column prop="fieldType" label="字段类型" width="120" align="center" />
<el-table-column prop="length" label="长度" width="80" align="center" />
<el-table-column prop="algorithm" label="加密算法" width="120" align="center" />
<el-table-column label="主键" width="60" align="left" fixed >
<template #default="scope">
<el-tag v-if="scope.row.primarykey === '1'" type="success"></el-tag>
</template>
</el-table-column>
<el-table-column prop="columnname" label="字段名" width="180" />
<el-table-column prop="typename" label="类型" width="120" />
<el-table-column prop="columnsize" label="长度" width="80" />
<el-table-column prop="maskingrulename" label="加密算法" width="120" align="center" />
<el-table-column label="密钥" width="120" align="center">
<template #default="{ row }">
<el-button type="text" @click="openEncryptionDialog(row)">设置</el-button>
<el-button v-if="row.secretkeyName" link type="primary" >{{ row.secretkeyName }}</el-button>
<el-button v-else link type="primary" @click="openEncryptionDialog(row)">设置</el-button>
</template>
</el-table-column>
<el-table-column prop="status" label="状态" width="100" align="center">
<el-table-column label="状态" width="100" align="center">
<template #default="{ row }">
<el-tag v-if="row.status === 'encrypted'" type="success" size="small">已加密</el-tag>
<el-tag v-else type="info" size="small">未加密</el-tag>
<span>{{ getFlagName(row.flag) }}</span>
</template>
</el-table-column>
<!-- 操作 -->
<el-table-column label="操作" width="100" align="center">
<template #default="{ row }">
<el-button v-if="row.secretkeyName && ['1', '5', '44', '10', '11'].includes(row.flag)" type="primary" size="small" @click="handleEditField(row)">解密</el-button>
<el-button v-if="row.secretkeyName && ['4', '6', '7', '9', '12'].includes(row.flag)" type="primary" size="small" @click="handleEditField(row)">加密</el-button>
</template>
</el-table-column>
<!-- 源长度 -->
<el-table-column label="源长度" width="100" align="center">
<template #default="{ row }">
<el-button link type="success" v-if="row.secretkeyName">{{ row.columnsize }}</el-button>
</template>
</el-table-column>
<!-- 右浮动列 -->
<el-table-column prop="comment" label="注释" align="left" min-width="200" />
<el-table-column prop="remarks" label="注释" align="left" min-width="200" />
<el-table-column label="描述信息" align="left" fixed="right">
<template #default="{ row }">
<el-input
......@@ -61,23 +78,22 @@
</template>
</el-table-column>
<el-table-column prop="plaintextProcess" label="明文处理" align="left" fixed="right"/>
</el-table>
<div
v-if="!isEditing"
class="table-mask-click"
@click="handleTableMaskClick"
style="position:absolute;top:0;left:0;width:100%;height:100%;background:rgba(255,255,255,0.01);z-index:11;cursor:not-allowed;"
></div>
</div>
<!-- 操作按钮区域 -->
<div class="action-buttons">
<el-button type="primary" @click="handleBatchEncrypt">批量加密</el-button>
<el-button type="primary" @click="handleBatchDecrypt">批量解密</el-button>
<el-button type="primary" @click="handleDeleteColumns">删除多余列</el-button>
<el-button
type="primary"
@click="toggleEditMode"
>
{{ isEditing ? '保存' : '编辑' }}
</el-button>
<el-button v-if="!isEditing" type="primary" @click="handleBatchEncrypt">批量加密</el-button>
<el-button v-if="!isEditing" type="primary" @click="handleBatchDecrypt">批量解密</el-button>
<el-button v-if="!isEditing" type="primary" @click="handleDeleteColumns">删除多余列</el-button>
<el-button v-if="!isEditing" type="primary" @click="toggleEditMode">编辑</el-button>
<el-button v-if="isEditing" type="info" @click="toggleEditMode">取消</el-button>
<el-button v-if="isEditing" type="primary" @click="handleSave">保存</el-button>
</div>
......@@ -92,33 +108,43 @@
<script setup>
import { ref, computed, reactive } from 'vue'
import EncryptionRuleDialog from './EncryptionRuleDialog.vue'
import { ElMessageBox } from 'element-plus'
const props = defineProps({
tableData: {
type: Array,
required: true,
default: () => [
{
pk: 'PK',
fieldName: 'table_id',
fieldType: 'BIGINT',
length: '19',
algorithm: '',
status: 'unencrypted',
comment: '编号',
description: '主键ID',
plaintextProcess: ''
},
// 其他数据行...
]
default: () => []
}
})
const emit = defineEmits(['batch-encrypt', 'batch-decrypt', 'delete-columns', 'edit-field', 'update-field'])
// 状态标识对象数组
const encryptFlag = [
{ value: '-2', label: '解密中' },
{ value: '-1', label: '加密中' },
{ value: '1', label: '加密完成' },
{ value: '5', label: '加密完成' },
{ value: '4', label: '加密失败' },
{ value: '44', label: '解密失败' },
{ value: '6', label: '解密完成' },
{ value: '7', label: '解密完成' },
{ value: '9', label: '加密替换失败' },
{ value: '10', label: '解密替换失败' },
{ value: '11', label: '解密校验失败' },
{ value: '12', label: '加密校验失败' }
]
/**
* 加密状态标识
*/
const getFlagName = (flag) => {
const found = encryptFlag.find(item => item.value === String(flag))
return found ? found.label : ''
}
// 搜索表单
const filterForm = reactive({
fieldName: '',
status: ''
flag: ''
})
// 编辑模式
......@@ -129,6 +155,7 @@ const tableRowClassName = ({ row, rowIndex }) => {
return row.status === 'encrypted' ? 'encrypted-row' : ''
}
// 处理搜索
const handleSearch = () => {
// 搜索逻辑已在计算属性中实现
......@@ -139,7 +166,6 @@ const toggleEditMode = () => {
isEditing.value = !isEditing.value
}
// 处理描述信息变更
const handleDescriptionChange = (row) => {
emit('update-field', row)
......@@ -161,15 +187,19 @@ const handleDeleteColumns = () => {
emit('delete-columns')
}
const handleSave = () => {
emit('save-changes')
}
// 过滤表格数据
const filteredTableData = computed(() => {
return props.tableData.filter(item => {
const matchesName = filterForm.fieldName
? item.fieldName.includes(filterForm.fieldName)
const matchesName = filterForm.columnname
? item.columnname.includes(filterForm.columnname)
: true
const matchesStatus = filterForm.status
? item.status === filterForm.status
const matchesStatus = filterForm.flag
? item.flag === filterForm.flag
: true
return matchesName && matchesStatus
......@@ -193,6 +223,10 @@ const handleRuleConfirm = (ruleData) => {
console.log('确认加密规则:', ruleData)
// 更新表格数据或调用API
}
const handleTableMaskClick = () => {
ElMessageBox.alert('当前是只读状态,编辑可点击编辑按钮进行编辑!')
}
</script>
<style scoped>
......@@ -235,4 +269,9 @@ const handleRuleConfirm = (ruleData) => {
color: #333;
font-weight: normal;
}
.table-mask-click {
/* 只拦截点击事件,不影响滚动和悬浮 */
pointer-events: auto;
}
</style>
\ No newline at end of file
......@@ -2,18 +2,23 @@
<div class="structure-tab">
<el-table
:data="tableData"
max-height="500px"
border
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa', color: '#333' }"
:row-style="{ height: '40px' }"
:cell-style="{ padding: '8px 0', textAlign: 'center' }"
>
<el-table-column prop="pk" label="主键" width="120" fixed/>
<el-table-column prop="fieldName" label="字段名" width="180" />
<el-table-column prop="comment" label="注释" min-width="200" />
<el-table-column prop="fieldType" label="类型" width="120" />
<el-table-column prop="length" label="长度" width="120" />
<el-table-column prop="precision" label="精度" width="120" />
<el-table-column label="主键" width="80" fixed>
<template #default="scope">
<el-tag v-if="scope.row.primarykey === '1'" type="success"></el-tag>
</template>
</el-table-column>
<el-table-column prop="columnname" label="字段名" width="180" />
<el-table-column prop="remarks" label="注释" min-width="200" />
<el-table-column prop="typename" label="类型" width="120" />
<el-table-column prop="columnsize" label="长度" width="120" />
<el-table-column prop="decimaldigits" label="精度" width="120" />
</el-table>
</div>
</template>
......@@ -23,18 +28,7 @@ const props = defineProps({
tableData: {
type: Array,
required: true,
default: () => [
{ pk: '', fieldName: 'business_name', comment: '生成业务名', fieldType: 'VARCHAR', length: '30', precision: '' },
{ pk: '', fieldName: 'business_name_...', comment: '', fieldType: 'TEXT', length: '65535', precision: '' },
{ pk: '', fieldName: 'class_name', comment: '实体类名称', fieldType: 'VARCHAR', length: '100', precision: '' },
{ pk: '', fieldName: 'create_by', comment: '创建者', fieldType: 'VARCHAR', length: '64', precision: '' },
{ pk: '', fieldName: 'create_time', comment: '创建时间', fieldType: 'DATETIME', length: '19', precision: '' },
{ pk: '', fieldName: 'function_author', comment: '生成功能作者', fieldType: 'VARCHAR', length: '50', precision: '' },
{ pk: '', fieldName: 'function_name', comment: '生成功能名', fieldType: 'VARCHAR', length: '50', precision: '' },
{ pk: '', fieldName: 'gen_path', comment: '生成路径(不填...', fieldType: 'VARCHAR', length: '200', precision: '' },
{ pk: '', fieldName: 'gen_type', comment: '生成代码方式(0...', fieldType: 'CHAR', length: '1', precision: '' },
{ pk: '', fieldName: 'module_name', comment: '生成模块名', fieldType: 'VARCHAR', length: '30', precision: '' }
]
default: () => []
}
})
</script>
......
<template>
<div class="table-info-tab">
<!-- 表基本信息 -->
<el-descriptions
title="表基本信息"
title=""
border
:column="1"
size="medium"
>
<el-descriptions-item label="字段数">224</el-descriptions-item>
<el-descriptions-item label="加密表数量">0</el-descriptions-item>
<el-descriptions-item label="加密字段数量">0</el-descriptions-item>
<el-descriptions-item label="未加密表数量">20</el-descriptions-item>
<el-descriptions-item label="未加密字段数量">224</el-descriptions-item>
<el-descriptions-item label="操作人">admin</el-descriptions-item>
<el-descriptions-item label="操作时间">2023-05-15 14:30:22</el-descriptions-item>
<el-descriptions-item label="字段数">{{ nodeData.totalColumnCount }}</el-descriptions-item>
<el-descriptions-item label="未加密字段数量">{{ nodeData.unencryptColumnCount }}</el-descriptions-item>
<el-descriptions-item label="加密字段数量">{{ nodeData.encryptColumnCount }}</el-descriptions-item>
<el-descriptions-item label="操作人">{{ nodeData.operator }}</el-descriptions-item>
<el-descriptions-item label="操作时间">{{ nodeData.operationTime }}</el-descriptions-item>
</el-descriptions>
</div>
</template>
<script setup>
// 可以留空,因为数据是静态的
const props = defineProps({
nodeData: {
type: Object,
default: () => ({})
}
})
</script>
<style scoped>
......
......@@ -27,6 +27,18 @@
<span class="custom-tree-node">
<i :class="getNodeIcon(data.type)" class="node-icon"></i>
<span>{{ node.label }}</span>
<template v-if="data.type === 'category'">
<i class="el-icon-collection icon-category" style="margin-left:6px;color:#F7BA2A;font-size:16px;"></i>
</template>
<template v-if="data.type === 'system'">
<i class="el-icon-s-platform icon-system" style="margin-left:6px;color:#409EFF;font-size:16px;"></i>
</template>
<template v-if="data.type === 'database'">
<i class="el-icon-s-data icon-database" style="margin-left:6px;color:#67C23A;font-size:16px;"></i>
</template>
<template v-if="data.type === 'table'">
<i class="el-icon-s-grid icon-table" style="margin-left:6px;color:#E6A23C;font-size:16px;"></i>
</template>
</span>
</template>
</el-tree>
......@@ -125,9 +137,11 @@ const handleNodeClick = (data) => {
<style scoped>
.tree-filter-container {
max-height: 700px;
overflow-y: auto;
width: 100%;
height: 100%;
background-color: #f5f5f5;
/* background-color: #f5f5f5; */
padding: 10px;
border-right: 1px solid #e6e6e6;
}
......@@ -152,6 +166,19 @@ const handleNodeClick = (data) => {
color: #606266;
}
.icon-category {
vertical-align: middle;
}
.icon-system {
vertical-align: middle;
}
.icon-database {
vertical-align: middle;
}
.icon-table {
vertical-align: middle;
}
:deep(.el-tree-node__content) {
height: 36px;
}
......
......@@ -59,7 +59,7 @@
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
<span>Copyright © 2018-2025 All Rights Reserved.</span>
</div>
</div>
</template>
......@@ -86,8 +86,8 @@ const appStore = useAppStore()
const { proxy } = getCurrentInstance()
const loginForm = ref({
username: "admin",
password: "admin123",
username: "",
password: "",
rememberMe: false,
code: "",
uuid: ""
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论