Commit 9e370fdb by 周海峰

加密设置

parent 434380b0
...@@ -1172,3 +1172,77 @@ export function save(data) { ...@@ -1172,3 +1172,77 @@ export function save(data) {
}) })
} }
/**
* 单字段加密
* @param {*} data
*{
* columnName: "post_name"
* columnSize: "50"
* columnType: "VARCHAR"
* dataSystemId: "ff8081819882f3cd019883210d130015"
* flag: 0
* map: {
* dataSystemId: "ff8081819882f3cd019883210d130015"
* projectId: "fda50ea9-b7fa-4fe4-b368-eebeffded6b6"
* map: {
* ry.sys_post.post_name: {
* columnType: "VARCHAR",
* columnSize: "50",
* describe_info: "66",
* encryptionSecretKeyId: "ff80818198cf9ab10198db90819905ea",
* flag: "1"
* }
* }
* primaryKeys: ["post_id"]
* projectId: "fda50ea9-b7fa-4fe4-b368-eebeffded6b6"
* schema: "ry"
* secretKeyId: "ff80818198cf9ab10198db90819905ea"
* tableName: "sys_post"
*}
* @returns {"code":"POP_00014","msg":"成功。","totalCount":0,"flag":true,"data":null}
*/
export function checkSingleEncOrDecColumn(data) {
return request({
url: '/core/encryption/checkSingleEncOrDecColumn',
method: 'POST',
data: data
})
}
/**
* 加载列信息
* @param {*} data
*{
* columnName: "post_name"
* columnSize: "50"
* columnType: "VARCHAR"
* dataSystemId: "ff8081819882f3cd019883210d130015"
* flag: 0
* map: {
* dataSystemId: "ff8081819882f3cd019883210d130015"
* projectId: "fda50ea9-b7fa-4fe4-b368-eebeffded6b6"
* map: {
* ry.sys_post.post_name: {
* columnType: "VARCHAR",
* columnSize: "50",
* describe_info: "66",
* encryptionSecretKeyId: "ff80818198cf9ab10198db90819905ea",
* flag: "1"
* }
* }
* primaryKeys: ["post_id"]
* projectId: "fda50ea9-b7fa-4fe4-b368-eebeffded6b6"
* schema: "ry"
* secretKeyId: "ff80818198cf9ab10198db90819905ea"
* tableName: "sys_post"
*}
*
* @returns {"code":"POP_00014","msg":"成功。","totalCount":0,"flag":true,"data":null}
*/
export function loadingColumn(data) {
return request({
url: '/core/encryption/loadingColumn',
method: 'POST',
data: data
})
}
\ No newline at end of file
<script setup name="Classification"> <script setup name="Classification">
import { ElMessageBox, ElMessage } from 'element-plus' import { ElMessageBox, ElMessage } from 'element-plus'
import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted, watch } from 'vue' import { ref, toRefs, reactive, getCurrentInstance, proxyRefs, onMounted, watch, provide, nextTick } from 'vue'
import TreeFilter from './modules/TreeFilter.vue' import TreeFilter from './modules/TreeFilter.vue'
import BasicInfoTab from './modules/BasicInfoTab.vue' import BasicInfoTab from './modules/BasicInfoTab.vue'
import TableInfoTab from './modules/TableInfoTab.vue' import TableInfoTab from './modules/TableInfoTab.vue'
import StructureTab from './modules/StructureTab.vue' import StructureTab from './modules/StructureTab.vue'
import EncryptionTab from './modules/EncryptionTab.vue' import EncryptionTab from './modules/EncryptionTab.vue'
import { changeRoute } from '@/utils/switchRoute' import { changeRoute } from '@/utils/switchRoute'
import { useRouter } from 'vue-router'
import useAppStore from '@/store/modules/app'
import usePermissionStore from '@/store/modules/permission'
import { query, getClassifyEnable, getGlobalOriginalConfig, changeGlobalOriginalConfig, queryDatasystemInfo, import { query, getClassifyEnable, getGlobalOriginalConfig, changeGlobalOriginalConfig, queryDatasystemInfo,
queryShemas, queryTables, querytableInfo, getfield, queryShemas, queryTables, querytableInfo, getfield,
queryOriginalList, queryEncryptionList save
} from '@/api/classification/classification.js' } from '@/api/classification/classification.js'
import { id } from 'element-plus/es/locales.mjs'
const route = useRoute() const route = useRoute()
// 字段加密信息子组件列表
const encryptionTabRef = ref()
const projectId = ref('') const projectId = ref('')
// 树形数据 // 树形数据
const treeData = ref([]) const treeData = ref([])
...@@ -25,6 +23,7 @@ const basicInfoData = ref({}) ...@@ -25,6 +23,7 @@ const basicInfoData = ref({})
const activeTab = ref('basic') const activeTab = ref('basic')
// 当前选中的节点数据 // 当前选中的节点数据
const currentNodeData = ref(null) const currentNodeData = ref(null)
provide('currentNodeData', currentNodeData)
const currentNodeLevel = computed(() => { const currentNodeLevel = computed(() => {
if (!currentNodeData.value) return 1 if (!currentNodeData.value) return 1
if (currentNodeData.value.type === 'system') return 1 if (currentNodeData.value.type === 'system') return 1
...@@ -36,8 +35,7 @@ const currentNodeLevel = computed(() => { ...@@ -36,8 +35,7 @@ const currentNodeLevel = computed(() => {
// 当前表结构数据 (匹配图片中的gen_table结构) // 当前表结构数据 (匹配图片中的gen_table结构)
const currentTableStructure = ref([]) const currentTableStructure = ref([])
// 当前表字段加密配置
const originalList = ref([])
// 监听 currentNodeLevel 和 currentNodeData,一级节点时自动查详情 // 监听 currentNodeLevel 和 currentNodeData,一级节点时自动查详情
watch([currentNodeLevel, currentNodeData, activeTab], async ([level, node, tab]) => { watch([currentNodeLevel, currentNodeData, activeTab], async ([level, node, tab]) => {
...@@ -82,44 +80,10 @@ watch([currentNodeLevel, currentNodeData, activeTab], async ([level, node, tab]) ...@@ -82,44 +80,10 @@ watch([currentNodeLevel, currentNodeData, activeTab], async ([level, node, tab])
//查询字段加密配置 //查询字段加密配置
if (level === 4 && node && tab === 'encryption') { if (level === 4 && node && tab === 'encryption') {
console.log('查询字段加密配置', node) nextTick(() => {
encryptionTabRef.value.getTableData()
// 查询字段原始值配置&字段加密配置 })
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 () => { onMounted(async () => {
...@@ -150,41 +114,41 @@ onMounted(async () => { ...@@ -150,41 +114,41 @@ onMounted(async () => {
// 树节点点击处理 // 树节点点击处理
const handleNodeClick = async (data) => { const handleNodeClick = async (data) => {
currentNodeData.value = data currentNodeData.value = data
// 2. 点击一层系统数据,查 schemas // 2. 点击一层系统数据,查 schemas
if (data.type === 'system') { if (data.type === 'system') {
activeTab.value = 'basic' activeTab.value = 'basic'
const res = await queryShemas({ const res = await queryShemas({
dataSystemId: data.tid, dataSystemId: data.tid,
dataType: data.dbtype, dataType: data.dbtype,
projectid: projectId.value projectid: projectId.value
}) })
if (res && res.data) { if (res && res.data) {
data.children = res.data.map(schema => ({ data.children = res.data.map(schema => ({
id: uuid(), id: uuid(),
...schema, ...schema,
type: 'database', type: 'database',
label: schema.text, label: schema.text,
parent: data, parent: data,
children: [ children: [
{ {
id: uuid(), id: uuid(),
label: '表', label: '表',
type: 'category', type: 'category',
parent: { parent: {
...schema, ...schema,
type: 'database', type: 'database',
label: schema.text, label: schema.text,
parent: data, parent: data,
tid: data.tid, tid: data.tid,
dbservername: schema.text dbservername: schema.text
}, },
children: [] children: []
} }
] ]
})) }))
treeData.value = [...treeData.value] // 触发视图更新 treeData.value = [...treeData.value] // 触发视图更新
} }
} }
// 3. 点击三层 category,查表 // 3. 点击三层 category,查表
if (data.type === 'category' && data.parent) { if (data.type === 'category' && data.parent) {
...@@ -232,32 +196,6 @@ const handleDecryptChange = async (val) => { ...@@ -232,32 +196,6 @@ const handleDecryptChange = async (val) => {
} }
} }
// 批量加密
const handleBatchEncrypt = () => {
console.log('批量加密', currentNodeData.value)
}
// 批量解密
const handleBatchDecrypt = () => {
console.log('批量解密', currentNodeData.value)
}
// 删除多余列
const handleDeleteColumns = () => {
console.log('删除多余列', currentNodeData.value)
}
const handleSave = () => {
console.log('保存更改', currentNodeData.value)
}
// 编辑字段
const handleEditField = (field) => {
console.log('编辑字段', field)
}
function pageProjectManage() { function pageProjectManage() {
changeRoute() changeRoute()
router.push({ router.push({
...@@ -343,12 +281,7 @@ function uuid() { ...@@ -343,12 +281,7 @@ function uuid() {
<!-- 字段加密配置Tab (仅4级节点显示) --> <!-- 字段加密配置Tab (仅4级节点显示) -->
<el-tab-pane label="字段加密配置" name="encryption" v-if="currentNodeLevel === 4"> <el-tab-pane label="字段加密配置" name="encryption" v-if="currentNodeLevel === 4">
<EncryptionTab <EncryptionTab
:table-data="originalList" ref="encryptionTabRef"
@batch-encrypt="handleBatchEncrypt"
@batch-decrypt="handleBatchDecrypt"
@delete-columns="handleDeleteColumns"
@save-changes="handleSave"
@edit-field="handleEditField"
v-if="activeTab === 'encryption'" v-if="activeTab === 'encryption'"
/> />
</el-tab-pane> </el-tab-pane>
......
...@@ -10,30 +10,35 @@ ...@@ -10,30 +10,35 @@
<div class="selection-section"> <div class="selection-section">
<!-- 左侧加密规则选择 --> <!-- 左侧加密规则选择 -->
<div class="rule-selection"> <div class="rule-selection">
<div class="section-title">选择加密规则</div> <div class="section-title gradient-title">
<el-radio-group v-model="selectedRule" class="rule-radio-group"> <i class="el-icon-lock" style="margin-right:6px;color:#409EFF;font-size:18px;"></i>
选择加密规则
</div>
<el-radio-group v-model="fieldData.maskingruleid" class="rule-radio-group">
<el-radio <el-radio
v-for="rule in encryptionRules" v-for="rule in encryptionRules"
:key="rule.id" :key="rule.id"
:label="rule.id" :value="rule.id"
class="rule-radio" class="rule-radio"
> >
{{ rule.name }} {{ rule.name }}
<span style="color: aqua;">{{ rule.list.length || 0 }}</span>
</el-radio> </el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<!-- 分割线 --> <!-- 分割线 -->
<div class="divider"></div> <div class="divider"></div>
<!-- 右侧加密密钥选择 --> <!-- 右侧加密密钥选择 -->
<div class="key-selection"> <div class="key-selection">
<div class="section-title">选择加密密钥</div> <div class="section-title gradient-title">
<el-radio-group v-model="selectedKey" class="key-radio-group"> <i class="el-icon-key" style="margin-right:6px;color:#67C23A;font-size:18px;"></i>
选择加密密钥
</div>
<el-radio-group v-model="fieldData.encryptionSecretKeyId" @change="handleKeyChange" class="key-radio-group">
<el-radio <el-radio
v-for="key in currentKeys" v-for="key in currentKeys"
:key="key.id" :key="key.id"
:label="key.id" :value="key.id"
class="key-radio" class="key-radio"
> >
{{ key.name }} {{ key.name }}
...@@ -48,18 +53,30 @@ ...@@ -48,18 +53,30 @@
<!-- 加密位置 --> <!-- 加密位置 -->
<div class="config-item"> <div class="config-item">
<span class="required-label">*加密位置:</span> <span class="required-label">*加密位置:</span>
<el-select v-model="ruleConfig.positionType" style="width: 120px"> <el-select v-model="fieldData.keepfirst" style="width: 120px">
<el-option label="保留前" value="prefix" /> <el-option label="保留前" value="0" />
<el-option label="保留后" value="suffix" /> <el-option label="保留后" value="1" />
<el-option label="既保留前" value="2" />
</el-select> </el-select>
<el-input-number <el-input-number
v-model="ruleConfig.position" v-model="fieldData.encdigit"
:min="0" :min="0"
:max="100" :max="100"
controls-position="right" controls-position="right"
style="width: 100px; margin-left: 10px;" style="width: 100px; margin-left: 10px;"
/> />
<span class="unit"></span> <span class="unit"></span>
<span v-if="fieldData.keepfirst === '2'">
<span class="unit">又保留后</span>
<el-input-number
v-model="fieldData.twoindex"
:min="0"
:max="100"
controls-position="right"
style="width: 100px; margin-left: 10px;"
/>
<span class="unit"></span>
</span>
</div> </div>
</div> </div>
<div class="config-row"> <div class="config-row">
...@@ -67,7 +84,7 @@ ...@@ -67,7 +84,7 @@
<div class="config-item"> <div class="config-item">
<span class="label">源长度:</span> <span class="label">源长度:</span>
<el-input-number <el-input-number
v-model="ruleConfig.sourceLength" v-model="fieldData.columnSize"
:min="0" :min="0"
:max="1000" :max="1000"
controls-position="right" controls-position="right"
...@@ -90,7 +107,7 @@ ...@@ -90,7 +107,7 @@
</div> </div>
</div> </div>
<div class="action-row"> <div class="action-row">
<el-checkbox v-model="supportFuzzy">支持模糊</el-checkbox> <el-checkbox v-model="fieldData.isLike" true-value="1" false-value="0">支持模糊</el-checkbox>
<div class="action-buttons"> <div class="action-buttons">
<el-button @click="resetRules">重置规则</el-button> <el-button @click="resetRules">重置规则</el-button>
<el-button type="primary" @click="confirmRules">确定规则</el-button> <el-button type="primary" @click="confirmRules">确定规则</el-button>
...@@ -102,8 +119,8 @@ ...@@ -102,8 +119,8 @@
</template> </template>
<script setup> <script setup>
import { ref, computed, watch } from 'vue' import { ref, computed, inject, onMounted, nextTick } from 'vue'
import { encryptionQuery, queryExtendColumnSize } from '@/api/classification/classification.js'
const props = defineProps({ const props = defineProps({
visible: { visible: {
type: Boolean, type: Boolean,
...@@ -111,11 +128,29 @@ const props = defineProps({ ...@@ -111,11 +128,29 @@ const props = defineProps({
}, },
fieldData: { fieldData: {
type: Object, type: Object,
default: () => ({}) default: () => ({
columnname: '', // 字段
columnSize: '', // 长度
realitycolumnsize: '',
columnType: '', // 类型
note: '',
maskingruleid: '',//加密规则
maskingrulename: '',
encryptionSecretKeyId: '', // 密钥ID
secretkeyName: '', // 密钥名称
isLike: '',
encdigit: '',
keepfirst: '',
twoindex: '',
flag: "0"
})
} }
}) })
const emit = defineEmits(['update:visible', 'confirm']) // 获取父组件 provide 的 currentNodeData(响应式)
const currentNodeData = inject('currentNodeData')
// console.log(' currentNodeData.value', currentNodeData.value)
const emit = defineEmits(['update:visible', 'confirm', 'reset'])
// 控制弹窗显示 // 控制弹窗显示
const dialogVisible = computed({ const dialogVisible = computed({
...@@ -124,81 +159,70 @@ const dialogVisible = computed({ ...@@ -124,81 +159,70 @@ const dialogVisible = computed({
}) })
// 加密规则数据 // 加密规则数据
const encryptionRules = ref([ const encryptionRules = ref([])
{ id: 'name', name: '姓名加密规则' },
{ id: 'gender', name: '性别加密规则' }
])
// 加密密钥数据
const encryptionKeys = ref({
name: [
{ id: 'name_key1', name: '姓名加密密钥1' },
{ id: 'name_key2', name: '姓名加密密钥2' }
],
gender: [
{ id: 'gender_key1', name: '性别加密密钥1' },
{ id: 'gender_key2', name: '性别加密密钥2' }
]
})
// 当前选中的规则
const selectedRule = ref('name')
// 当前选中的密钥
const selectedKey = ref('')
// 当前显示的密钥列表 // 当前显示的密钥列表
const currentKeys = computed(() => { const currentKeys = computed(() => {
return encryptionKeys.value[selectedRule.value] || [] const rule = encryptionRules.value.find(r => r.id === props.fieldData.maskingruleid)
props.fieldData.maskingrulename = rule ? rule.name : ''
return rule && rule.list ? rule.list.map(key => ({
id: key.id,
name: key.secret_key_name
})) : []
}) })
// 加密配置 const handleKeyChange = (value) => {
const ruleConfig = ref({ const selectedKey = currentKeys.value.find(key => key.id === value)
positionType: 'prefix', props.fieldData.secretkeyName = selectedKey ? selectedKey.name : ''
position: 0, }
sourceLength: 100
onMounted(async () => {
const res = await encryptionQuery()
if (res && res.data) {
// 处理加密规则
encryptionRules.value = res.data.map(item => ({
id: item.id,
name: item.encryption_name,
list: item.list || []
}))
}
}) })
// 加密后长度 // 加密后长度
const encryptedLength = ref('') const encryptedLength = ref('')
// 是否支持模糊
const supportFuzzy = ref(false)
// 监听规则变化,自动选择第一个密钥
watch(selectedRule, (newVal) => {
if (currentKeys.value.length > 0) {
selectedKey.value = currentKeys.value[0].id
}
}, { immediate: true })
// 计算加密后长度 // 计算加密后长度
const calculateLength = () => { const calculateLength = async() => {
if (!props.fieldData || !props.fieldData.encryptionSecretKeyId) {
encryptedLength.value = ''
return
}
// 这里应该是实际的加密长度计算逻辑 // 这里应该是实际的加密长度计算逻辑
encryptedLength.value = Math.floor(ruleConfig.value.sourceLength * 0.8) const res = await queryExtendColumnSize({
projectid: currentNodeData.value.parent?.parent?.parent?.project_id,
datasystemid: currentNodeData.value.parent?.parent?.tid,
tablecat: currentNodeData.value.parent?.parent?.label,
tablename: currentNodeData.value.label,
columnname: props.fieldData.columnname,
columnsize: String(props.fieldData.columnSize),
columntype: props.fieldData.columnType,
dbtype: currentNodeData.value.parent?.parent?.parent?.dbtype,
islike: props.fieldData.isLike,
encryptionsecretkeyid: props.fieldData.encryptionSecretKeyId
})
encryptedLength.value = res.data?.extendcolumnsize
} }
// 重置规则 // 重置规则
const resetRules = () => { const resetRules = () => {
selectedRule.value = 'name' emit('reset')
ruleConfig.value = { dialogVisible.value = false
positionType: 'prefix',
position: 0,
sourceLength: 100
}
encryptedLength.value = ''
supportFuzzy.value = false
} }
// 确认规则 // 确认规则
const confirmRules = () => { const confirmRules = () => {
emit('confirm', { emit('confirm')
rule: selectedRule.value,
key: selectedKey.value,
config: ruleConfig.value,
supportFuzzy: supportFuzzy.value,
encryptedLength: encryptedLength.value
})
dialogVisible.value = false dialogVisible.value = false
} }
...@@ -206,6 +230,11 @@ const confirmRules = () => { ...@@ -206,6 +230,11 @@ const confirmRules = () => {
const handleClose = (done) => { const handleClose = (done) => {
done() done()
} }
defineExpose({
calculateLength
})
</script> </script>
<style scoped> <style scoped>
...@@ -239,9 +268,23 @@ const handleClose = (done) => { ...@@ -239,9 +268,23 @@ const handleClose = (done) => {
color: #333; color: #333;
} }
.gradient-title {
background: linear-gradient(90deg, #e3f0ff 0%, #f5fff7 100%);
border-radius: 6px;
padding: 6px 12px;
display: flex;
align-items: center;
font-size: 15px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
}
.rule-radio-group, .key-radio-group { .rule-radio-group, .key-radio-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: flex-start;
margin-left: 24px;
} }
.rule-radio, .key-radio { .rule-radio, .key-radio {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论