Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
N
nse-ui
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
吴超
nse-ui
Commits
c55f569c
Commit
c55f569c
authored
Aug 22, 2025
by
ningjihai
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
123
parent
265405b7
显示空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
515 行增加
和
34 行删除
+515
-34
src/views/desensitizationStrategy/DesensitizationStrategy/QueryForm.vue
+0
-0
src/views/desensitizationStrategy/DesensitizationStrategy/index.vue
+0
-0
src/views/desensitizationStrategy/DesensitizationStrategy/list.vue
+0
-0
src/views/desensitizationStrategy/DesensitizationStrategy/modules/AddStrategyDialog.vue
+127
-34
src/views/desensitizationStrategy/DesensitizationStrategy/modules/DesensitizationRuleDialog.vue
+388
-0
src/views/desensitizationStrategy/DesensitizationStrategy/脱敏策略管理.md
+0
-0
没有找到文件。
src/views/desensitizationStrategy/QueryForm.vue
→
src/views/desensitizationStrategy/
DesensitizationStrategy/
QueryForm.vue
View file @
c55f569c
File moved
src/views/desensitizationStrategy/index.vue
→
src/views/desensitizationStrategy/
DesensitizationStrategy/
index.vue
View file @
c55f569c
File moved
src/views/desensitizationStrategy/list.vue
→
src/views/desensitizationStrategy/
DesensitizationStrategy/
list.vue
View file @
c55f569c
File moved
src/views/desensitizationStrategy/modules/AddStrategyDialog.vue
→
src/views/desensitizationStrategy/
DesensitizationStrategy/
modules/AddStrategyDialog.vue
View file @
c55f569c
...
@@ -2,12 +2,12 @@
...
@@ -2,12 +2,12 @@
<el-dialog
<el-dialog
v-model=
"dialogVisible"
v-model=
"dialogVisible"
:title=
"currentStep === 1 ? '添加策略 - 步骤1/2' : '添加策略 - 步骤2/2'"
:title=
"currentStep === 1 ? '添加策略 - 步骤1/2' : '添加策略 - 步骤2/2'"
width=
"80
0px
"
width=
"80
%
"
:before-close=
"handleClose"
:before-close=
"handleClose"
>
>
<!-- 步骤1:基本信息 -->
<!-- 步骤1:基本信息 -->
<div
v-if=
"currentStep === 1"
class=
"step-content"
>
<div
v-if=
"currentStep === 1"
class=
"step-content"
>
<el-form
:model=
"formData"
:rules=
"rules"
ref=
"step1Form"
>
<el-form
:model=
"formData"
:rules=
"rules"
ref=
"step1Form"
label-width=
"120px"
>
<el-form-item
label=
"策略名称"
prop=
"name"
>
<el-form-item
label=
"策略名称"
prop=
"name"
>
<el-input
<el-input
v-model=
"formData.name"
v-model=
"formData.name"
...
@@ -32,7 +32,11 @@
...
@@ -32,7 +32,11 @@
<div
v-else
class=
"step-content"
>
<div
v-else
class=
"step-content"
>
<div
class=
"version-select"
>
<div
class=
"version-select"
>
<span>
根据发现版本设置脱敏:
</span>
<span>
根据发现版本设置脱敏:
</span>
<el-select
v-model=
"selectedVersion"
placeholder=
"选择发现版本"
>
<div
class=
"flex-container align-center"
>
<div>
选择发现版本
</div>
<el-select
class=
"version-select-content flex1"
v-model=
"selectedVersion"
placeholder=
"选择发现版本"
>
<el-option
label=
"无版本"
value=
""
/>
<el-option
label=
"无版本"
value=
""
/>
<el-option
<el-option
v-for=
"version in versions"
v-for=
"version in versions"
...
@@ -43,6 +47,8 @@
...
@@ -43,6 +47,8 @@
</el-select>
</el-select>
</div>
</div>
</div>
<div
class=
"field-selection"
>
<div
class=
"field-selection"
>
<div
class=
"tree-container"
>
<div
class=
"tree-container"
>
<el-tree
<el-tree
...
@@ -54,32 +60,17 @@
...
@@ -54,32 +60,17 @@
</div>
</div>
<el-divider
direction=
"vertical"
/>
<el-divider
direction=
"vertical"
/>
<div
class=
"table-container"
>
<div
class=
"table-container"
>
<el-table
:data=
"tableFields"
border
style=
"width: 100%"
>
<el-table
:data=
"tableFields"
border
style=
"width: 100%"
height=
"400px"
>
<el-table-column
prop=
"isPk"
label=
"主键"
width=
"80"
align=
"center"
>
<el-table-column
prop=
"isPk"
label=
"主键"
width=
"80"
align=
"center"
fixed
>
<template
#
default=
"
{ row }">
<template
#
default=
"
{ row }">
<span
v-if=
"row.isPk"
>
PK
</span>
<span
v-if=
"row.isPk"
>
PK
</span>
</
template
>
</
template
>
</el-table-column>
</el-table-column>
<el-table-column
prop=
"name"
label=
"字段名"
width=
"150"
/>
<el-table-column
prop=
"name"
label=
"字段名"
min-widthwidth=
"150"
/>
<el-table-column
prop=
"comment"
label=
"注释"
width=
"150"
/>
<el-table-column
prop=
"comment"
label=
"注释"
min-width=
"150"
/>
<el-table-column
prop=
"dataType"
label=
"数据域"
width=
"120"
/>
<el-table-column
prop=
"dataType"
label=
"数据域"
min-width=
"120"
/>
<el-table-column
label=
"脱敏算法"
width=
"180"
>
<el-table-column
prop=
"algorithm"
label=
"脱敏算法"
min-width=
"180"
/>
<
template
#
default=
"{ row }"
>
<el-table-column
label=
"操作"
width=
"80"
align=
"center"
fixed=
"right"
>
<el-select
v-model=
"row.algorithm"
placeholder=
"选择算法"
size=
"small"
>
<el-option
v-for=
"algo in algorithms"
:key=
"algo.value"
:label=
"algo.label"
:value=
"algo.value"
/>
</el-select>
</
template
>
</el-table-column>
<el-table-column
label=
"操作"
width=
"80"
align=
"center"
>
<
template
#
default=
"{ row }"
>
<
template
#
default=
"{ row }"
>
<el-button
type=
"text"
size=
"small"
@
click=
"handleSet(row)"
<el-button
type=
"text"
size=
"small"
@
click=
"handleSet(row)"
>
设置
</el-button
>
设置
</el-button
...
@@ -115,14 +106,25 @@
...
@@ -115,14 +106,25 @@
</div>
</div>
</
template
>
</
template
>
</el-dialog>
</el-dialog>
<!-- 脱敏规则设置弹窗 -->
<DesensitizationRuleDialog
v-model=
"desensitizationDialogVisible"
:current-field=
"currentField"
@
confirm=
"handleRuleConfirm"
/>
</template>
</template>
<
script
setup
>
<
script
setup
>
import
DesensitizationRuleDialog
from
'./DesensitizationRuleDialog.vue'
;
import
{
ref
,
reactive
}
from
'vue'
;
import
{
ref
,
reactive
}
from
'vue'
;
import
{
ElMessage
}
from
'element-plus'
;
import
{
ElMessage
}
from
'element-plus'
;
const
dialogVisible
=
ref
(
false
);
const
dialogVisible
=
ref
(
false
);
const
currentStep
=
ref
(
1
);
const
currentStep
=
ref
(
1
);
const
desensitizationDialogVisible
=
ref
(
false
);
const
currentField
=
ref
({});
// 表单数据
// 表单数据
const
formData
=
reactive
({
const
formData
=
reactive
({
...
@@ -142,22 +144,83 @@ const selectedVersion = ref('');
...
@@ -142,22 +144,83 @@ const selectedVersion = ref('');
const
versions
=
ref
([
'v1.0'
,
'v2.0'
]);
const
versions
=
ref
([
'v1.0'
,
'v2.0'
]);
const
treeData
=
ref
([
const
treeData
=
ref
([
{
{
id
:
'system1'
,
label
:
'若依测试系统1'
,
children
:
[
{
id
:
'ry'
,
id
:
'ry'
,
label
:
'若依配测系统'
,
label
:
'ry'
,
children
:
[
{
id
:
'tables'
,
label
:
'表'
,
children
:
[
children
:
[
{
{
id
:
'gen_table'
,
id
:
'gen_table'
,
label
:
'gen_table'
,
label
:
'gen_table'
,
type
:
'table'
,
type
:
'table'
},
},
{
{
id
:
'gen_table_column'
,
id
:
'gen_table_column'
,
label
:
'gen_table_column'
,
label
:
'gen_table_column'
,
type
:
'table'
,
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'
}
]
}
]
}
]
}
]);
]);
const
treeProps
=
{
const
treeProps
=
{
children
:
'children'
,
children
:
'children'
,
...
@@ -258,8 +321,18 @@ const fetchTableFields = (tableName) => {
...
@@ -258,8 +321,18 @@ const fetchTableFields = (tableName) => {
// 设置字段
// 设置字段
const
handleSet
=
(
row
)
=>
{
const
handleSet
=
(
row
)
=>
{
// 这里可以打开更详细的设置弹窗
currentField
.
value
=
row
;
console
.
log
(
'设置字段:'
,
row
);
desensitizationDialogVisible
.
value
=
true
;
};
// 处理规则确认
const
handleRuleConfirm
=
(
ruleData
)
=>
{
// 更新表格中的算法字段
const
fieldIndex
=
tableFields
.
value
.
findIndex
(
field
=>
field
.
name
===
ruleData
.
fieldName
);
if
(
fieldIndex
!==
-
1
)
{
tableFields
.
value
[
fieldIndex
].
algorithm
=
ruleData
.
algorithm
;
ElMessage
.
success
(
`字段
${
ruleData
.
fieldName
}
的脱敏规则已更新`
);
}
};
};
defineExpose
({
defineExpose
({
...
@@ -267,7 +340,7 @@ defineExpose({
...
@@ -267,7 +340,7 @@ defineExpose({
});
});
</
script
>
</
script
>
<
style
scoped
>
<
style
scoped
lang=
"scss"
>
.step-content
{
.step-content
{
min-height
:
400px
;
min-height
:
400px
;
}
}
...
@@ -283,7 +356,7 @@ defineExpose({
...
@@ -283,7 +356,7 @@ defineExpose({
.tree-container
{
.tree-container
{
width
:
250px
;
width
:
250px
;
height
:
100%
;
height
:
400px
;
overflow-y
:
auto
;
overflow-y
:
auto
;
padding-right
:
10px
;
padding-right
:
10px
;
}
}
...
@@ -303,4 +376,23 @@ defineExpose({
...
@@ -303,4 +376,23 @@ defineExpose({
height
:
100%
;
height
:
100%
;
margin
:
0
10px
;
margin
:
0
10px
;
}
}
.flex-container
{
display
:
flex
;
}
.align-center
{
align-items
:
center
;
}
.justify-between
{
justify-content
:
space-between
;
}
.flex1
{
flex
:
1
;
}
.version-select-content
{
margin-left
:
15px
;
}
</
style
>
</
style
>
\ No newline at end of file
src/views/desensitizationStrategy/DesensitizationStrategy/modules/DesensitizationRuleDialog.vue
0 → 100644
View file @
c55f569c
<
template
>
<el-dialog
v-model=
"dialogVisible"
title=
"设置脱敏规则"
width=
"800px"
:before-close=
"handleClose"
>
<div
class=
"desensitization-dialog"
>
<div
class=
"dialog-content"
>
<!-- 左侧:选择数据域(按照图片样式重写) -->
<div
class=
"data-domain-section"
>
<el-card>
<div
class=
"selector-header"
>
<span
class=
"selector-title"
>
选择数据域
</span>
</div>
<div
class=
"options-list"
>
<div
v-for=
"domain in dataDomains"
:key=
"domain.value"
class=
"option-item"
:class=
"
{ 'option-selected': selectedDomain === domain.value }"
@click="selectDomain(domain.value)"
>
<!-- 自定义单选按钮 -->
<div
class=
"custom-radio"
>
<div
class=
"radio-outer"
>
<div
class=
"radio-inner"
:class=
"
{ selected: selectedDomain === domain.value }">
</div>
</div>
</div>
<!-- 选项标签 -->
<span
class=
"option-label"
>
{{
domain
.
label
}}
</span>
</div>
</div>
</el-card>
</div>
<!--
<el-divider
direction=
"vertical"
/>
-->
<!-- 右侧:选择字段脱敏规则 -->
<div
class=
"algorithm-section"
>
<h4>
选择字段脱敏规则
</h4>
<div
class=
"algorithm-list"
>
<el-radio-group
v-model=
"selectedAlgorithm"
>
<el-radio
v-for=
"algorithm in currentAlgorithms"
:key=
"algorithm.value"
:label=
"algorithm.value"
class=
"algorithm-item"
>
{{
algorithm
.
label
}}
</el-radio>
</el-radio-group>
</div>
</div>
</div>
<el-divider
style=
"height: 1px;"
/>
<!-- 底部按钮 -->
<div
class=
"dialog-footer"
>
<el-button
@
click=
"resetRules"
>
重置规则
</el-button>
<el-button
type=
"primary"
@
click=
"confirmRules"
>
确定规则
</el-button>
</div>
</div>
</el-dialog>
</
template
>
<
script
setup
>
import
{
ref
,
computed
,
watch
,
onMounted
}
from
'vue'
import
{
ElMessage
}
from
'element-plus'
const
props
=
defineProps
({
modelValue
:
{
type
:
Boolean
,
default
:
false
},
currentField
:
{
type
:
Object
,
default
:
()
=>
({})
}
})
const
emit
=
defineEmits
([
'update:modelValue'
,
'confirm'
])
// 弹窗显示控制
const
dialogVisible
=
computed
({
get
:
()
=>
props
.
modelValue
,
set
:
(
value
)
=>
emit
(
'update:modelValue'
,
value
)
})
// 数据域选项(完全按照图片顺序)
const
dataDomains
=
ref
([
{
value
:
'wang'
,
label
:
'小王'
},
{
value
:
'test'
,
label
:
'测试数据域'
},
{
value
:
'general'
,
label
:
'通用规则'
},
{
value
:
'decrypt'
,
label
:
'解密数据'
},
{
value
:
'mixed_id'
,
label
:
'混合证件号'
},
{
value
:
'black_white'
,
label
:
'黑白名单'
},
{
value
:
'english_address'
,
label
:
'英文地址'
},
{
value
:
'name'
,
label
:
'姓名'
},
{
value
:
'phone'
,
label
:
'手机号码'
},
{
value
:
'age'
,
label
:
'年龄'
},
{
value
:
'business_license'
,
label
:
'营业执照'
},
{
value
:
'mixed_phone'
,
label
:
'混合电话号码'
}
])
// 脱敏算法选项
const
algorithmOptions
=
{
// 通用规则
general
:
[
{
value
:
'general_mask'
,
label
:
'通用掩码'
},
{
value
:
'general_encrypt'
,
label
:
'通用加密'
},
{
value
:
'general_hash'
,
label
:
'通用哈希'
}
],
// 姓名
name
:
[
{
value
:
'name_mask'
,
label
:
'姓名掩码'
},
{
value
:
'name_random'
,
label
:
'姓名随机替换'
},
{
value
:
'name_encrypt'
,
label
:
'姓名加密'
}
],
// 手机号码
phone
:
[
{
value
:
'phone_mask'
,
label
:
'手机号掩码'
},
{
value
:
'phone_encrypt'
,
label
:
'手机号加密'
},
{
value
:
'phone_hash'
,
label
:
'手机号哈希'
}
],
// 其他数据域的算法...
wang
:
[
{
value
:
'wang_mask'
,
label
:
'小王掩码'
},
{
value
:
'wang_encrypt'
,
label
:
'小王加密'
}
],
test
:
[
{
value
:
'test_mask'
,
label
:
'测试掩码'
},
{
value
:
'test_encrypt'
,
label
:
'测试加密'
}
],
// 默认算法
default
:
[
{
value
:
'mask'
,
label
:
'掩码处理'
},
{
value
:
'encrypt'
,
label
:
'加密处理'
},
{
value
:
'hash'
,
label
:
'哈希处理'
}
]
}
// 选中的数据域和算法
const
selectedDomain
=
ref
(
'general'
)
const
selectedAlgorithm
=
ref
(
''
)
// 计算当前可用的脱敏算法
const
currentAlgorithms
=
computed
(()
=>
{
return
algorithmOptions
[
selectedDomain
.
value
]
||
algorithmOptions
.
default
})
// 选择数据域
const
selectDomain
=
(
value
)
=>
{
selectedDomain
.
value
=
value
const
algorithms
=
currentAlgorithms
.
value
if
(
algorithms
.
length
>
0
)
{
selectedAlgorithm
.
value
=
algorithms
[
0
].
value
}
}
// 重置选择函数
const
resetSelection
=
()
=>
{
selectedDomain
.
value
=
'general'
const
algorithms
=
currentAlgorithms
.
value
if
(
algorithms
.
length
>
0
)
{
selectedAlgorithm
.
value
=
algorithms
[
0
].
value
}
}
// 根据算法推断数据域
const
inferDomainFromAlgorithm
=
(
algorithm
)
=>
{
for
(
const
[
domain
,
algorithms
]
of
Object
.
entries
(
algorithmOptions
))
{
if
(
algorithms
.
some
(
algo
=>
algo
.
value
===
algorithm
))
{
selectedDomain
.
value
=
domain
return
}
}
selectedDomain
.
value
=
'general'
}
// 监听当前字段变化,恢复已保存的规则
watch
(()
=>
props
.
currentField
,
(
newField
)
=>
{
if
(
newField
&&
newField
.
algorithm
)
{
selectedAlgorithm
.
value
=
newField
.
algorithm
inferDomainFromAlgorithm
(
newField
.
algorithm
)
}
else
{
resetSelection
()
}
},
{
immediate
:
true
})
// 组件挂载时初始化
onMounted
(()
=>
{
resetSelection
()
})
// 关闭弹窗
const
handleClose
=
()
=>
{
dialogVisible
.
value
=
false
}
// 重置规则
const
resetRules
=
()
=>
{
resetSelection
()
ElMessage
.
info
(
'规则已重置'
)
}
// 确定规则
const
confirmRules
=
()
=>
{
if
(
!
selectedAlgorithm
.
value
)
{
ElMessage
.
warning
(
'请选择脱敏规则'
)
return
}
emit
(
'confirm'
,
{
algorithm
:
selectedAlgorithm
.
value
,
domain
:
selectedDomain
.
value
,
fieldName
:
props
.
currentField
.
name
})
ElMessage
.
success
(
'脱敏规则设置成功'
)
dialogVisible
.
value
=
false
}
</
script
>
<
style
scoped
lang=
"scss"
>
.desensitization-dialog
{
.dialog-content
{
display
:
flex
;
height
:
400px
;
}
.data-domain-section
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
padding-right
:
20px
;
}
.algorithm-section
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
padding-left
:
20px
;
}
.selector-header
{
padding
:
0
0
16px
0
;
margin-bottom
:
8px
;
border-bottom
:
1px
dashed
#dcdfe6
;
.selector-title
{
font-size
:
16px
;
font-weight
:
900
;
color
:
#000000
;
line-height
:
1.5
;
display
:
block
;
}
}
.options-list
{
display
:
flex
;
flex-direction
:
column
;
gap
:
0
;
flex
:
1
;
overflow-y
:
auto
;
}
.option-item
{
display
:
flex
;
align-items
:
center
;
padding
:
12px
0
;
cursor
:
pointer
;
transition
:
background-color
0.2s
ease
;
border-bottom
:
1px
dashed
#e0e0e0
;
&:last-child
{
border-bottom
:
none
;
}
&
:hover
{
background-color
:
#f8f9fa
;
}
&
.option-selected
{
background-color
:
#f0f7ff
;
.option-label
{
color
:
#1890ff
;
font-weight
:
500
;
}
}
}
.custom-radio
{
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
margin-right
:
12px
;
width
:
20px
;
height
:
20px
;
flex-shrink
:
0
;
}
.radio-outer
{
width
:
16px
;
height
:
16px
;
border
:
2px
solid
#c0c4cc
;
border-radius
:
50%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
transition
:
all
0.2s
ease
;
.option-selected
&
{
border-color
:
#1890ff
;
background-color
:
#1890ff
;
}
}
.radio-inner
{
width
:
6px
;
height
:
6px
;
border-radius
:
50%
;
background-color
:
transparent
;
transition
:
background-color
0.2s
ease
;
&.selected
{
background-color
:
#ffffff
;
}
}
.option-label
{
font-size
:
14px
;
color
:
#606266
;
line-height
:
1.5
;
flex
:
1
;
user-select
:
none
;
.option-selected
&
{
color
:
#1890ff
;
}
}
h4
{
margin
:
0
0
16px
0
;
font-size
:
14px
;
font-weight
:
600
;
color
:
#606266
;
}
.algorithm-list
{
flex
:
1
;
overflow-y
:
auto
;
}
.algorithm-item
{
display
:
block
;
margin
:
8px
0
;
padding
:
8px
12px
;
border-radius
:
4px
;
transition
:
background-color
0.3s
;
&:hover
{
background-color
:
#f5f7fa
;
}
:deep
(
.el-radio__label
)
{
font-size
:
13px
;
}
}
.el-divider
{
//
height
:
360px
;
//
margin
:
0
20px
;
}
.dialog-footer
{
display
:
flex
;
justify-content
:
flex-end
;
margin-top
:
20px
;
gap
:
12px
;
}
}
</
style
>
\ No newline at end of file
src/views/desensitizationStrategy/脱敏策略管理.md
→
src/views/desensitizationStrategy/
DesensitizationStrategy/
脱敏策略管理.md
View file @
c55f569c
File moved
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论