mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat(permission): permission manage
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
import { request } from '@/utils/request'
|
||||
|
||||
export const getList = () => request.post('/ds_permission/list')
|
||||
export const savePermissions = (data: any) => request.post('/ds_permission/save', data)
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.6">
|
||||
<path d="M5.97112 5.23935L9.32987 1.8806C9.42751 1.78297 9.5858 1.78297 9.68343 1.8806L10.037 2.23415C10.1346 2.33178 10.1346 2.49007 10.037 2.5877L6.67823 5.94646L10.037 9.30522C10.1346 9.40285 10.1346 9.56114 10.037 9.65877L9.68343 10.0123C9.5858 10.11 9.42751 10.11 9.32987 10.0123L5.97112 6.65357L2.61236 10.0123C2.51473 10.11 2.35644 10.11 2.25881 10.0123L1.90525 9.65877C1.80762 9.56114 1.80762 9.40285 1.90525 9.30522L5.26401 5.94646L1.90525 2.5877C1.80762 2.49007 1.80762 2.33178 1.90525 2.23415L2.25881 1.8806C2.35644 1.78297 2.51473 1.78297 2.61236 1.8806L5.97112 5.23935Z" fill="#1F2329"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 727 B |
@@ -0,0 +1,5 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g opacity="0.6">
|
||||
<path d="M5.97112 5.23935L9.32987 1.8806C9.42751 1.78297 9.5858 1.78297 9.68343 1.8806L10.037 2.23415C10.1346 2.33178 10.1346 2.49007 10.037 2.5877L6.67823 5.94646L10.037 9.30522C10.1346 9.40285 10.1346 9.56114 10.037 9.65877L9.68343 10.0123C9.5858 10.11 9.42751 10.11 9.32987 10.0123L5.97112 6.65357L2.61236 10.0123C2.51473 10.11 2.35644 10.11 2.25881 10.0123L1.90525 9.65877C1.80762 9.56114 1.80762 9.40285 1.90525 9.30522L5.26401 5.94646L1.90525 2.5877C1.80762 2.49007 1.80762 2.33178 1.90525 2.23415L2.25881 1.8806C2.35644 1.78297 2.51473 1.78297 2.61236 1.8806L5.97112 5.23935Z" fill="#1F2329"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 727 B |
@@ -358,7 +358,29 @@
|
||||
"edit_row_permission": "Edit row permission",
|
||||
"add_column_permission": "Add column permission",
|
||||
"add_row_permission": "Add row permission",
|
||||
"no_fields_yet": "No fields yet"
|
||||
"no_fields_yet": "No fields yet",
|
||||
"filter_eq": "Equal to",
|
||||
"filter_not_eq": "Not equal to",
|
||||
"filter_lt": "Less than",
|
||||
"filter_le": "Less than or equal to",
|
||||
"filter_gt": "Greater than",
|
||||
"filter_ge": "Greater than or equal to",
|
||||
"filter_null": "Empty",
|
||||
"filter_not_null": "Not empty",
|
||||
"filter_empty": "Empty string",
|
||||
"filter_not_empty": "Not empty string",
|
||||
"filter_include": "Include",
|
||||
"filter_not_include": "Not included",
|
||||
"conditional_filtering": "Conditional filtering",
|
||||
"add_conditions": "Add conditions",
|
||||
"add_relationships": "Add relationships",
|
||||
"cannot_be_empty_": "Filter field cannot be empty",
|
||||
"cannot_be_empty_de_ruler": "Rule condition cannot be empty",
|
||||
"filter_value_can_null": "Filter value cannot be null",
|
||||
"filter_like": "Contains",
|
||||
"filter_not_like": "Does not contain",
|
||||
"filter_in": "Belongs to",
|
||||
"filter_not_in": "Does not belong to"
|
||||
},
|
||||
"chat": {
|
||||
"type": "Chart Type",
|
||||
|
||||
@@ -374,7 +374,29 @@
|
||||
"edit_row_permission": "编辑行权限",
|
||||
"add_column_permission": "添加列权限",
|
||||
"add_row_permission": "添加行权限",
|
||||
"no_fields_yet": "暂无字段"
|
||||
"no_fields_yet": "暂无字段",
|
||||
"filter_eq": "等于",
|
||||
"filter_not_eq": "不等于",
|
||||
"filter_lt": "小于",
|
||||
"filter_le": "小于等于",
|
||||
"filter_gt": "大于",
|
||||
"filter_ge": "大于等于",
|
||||
"filter_null": "为空",
|
||||
"filter_not_null": "不为空",
|
||||
"filter_empty": "空字符串",
|
||||
"filter_not_empty": "非空字符串",
|
||||
"filter_include": "包含",
|
||||
"filter_not_include": "不包含",
|
||||
"conditional_filtering": "条件筛选",
|
||||
"add_conditions": "添加条件",
|
||||
"add_relationships": "添加关系",
|
||||
"cannot_be_empty_": "过滤字段不能为空",
|
||||
"cannot_be_empty_de_ruler": "规则条件不能为空",
|
||||
"filter_value_can_null": "过滤值不能为空",
|
||||
"filter_like": "包含",
|
||||
"filter_not_like": "不包含",
|
||||
"filter_in": "属于",
|
||||
"filter_not_in": "不属于"
|
||||
},
|
||||
"chat": {
|
||||
"type": "图表类型",
|
||||
|
||||
@@ -45,7 +45,7 @@ const setUser = () => {
|
||||
</div>
|
||||
<div class="type-value">
|
||||
<span class="type">{{ $t('permission.permission_rule') }}</span>
|
||||
<span class="value"> {{ $t('permission.2', { msg: type }) }}</span>
|
||||
<span class="value"> {{ $t('permission.2', { msg: num }) }}</span>
|
||||
</div>
|
||||
<div class="type-value">
|
||||
<span class="type">{{ $t('permission.restricted_user') }}</span>
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
<template>
|
||||
<div class="select-user_permission">
|
||||
<p class="lighter-bold">{{ $t('permission.select_restricted_user') }}</p>
|
||||
<div v-loading="loading" class="flex border" style="height: 428px; border-radius: 6px">
|
||||
<div class="p-16 border-r">
|
||||
<el-input
|
||||
v-model="search"
|
||||
:validate-event="false"
|
||||
:placeholder="$t('datasource.search')"
|
||||
style="width: 364px"
|
||||
clearable
|
||||
>
|
||||
<template #prefix>
|
||||
<el-icon>
|
||||
<Search></Search>
|
||||
</el-icon>
|
||||
</template>
|
||||
</el-input>
|
||||
<div class="mt-8 max-height_workspace">
|
||||
<el-checkbox
|
||||
v-if="!search"
|
||||
v-model="checkAll"
|
||||
class="mb-8"
|
||||
:indeterminate="isIndeterminate"
|
||||
@change="handleCheckAllChange"
|
||||
>
|
||||
{{ $t('datasource.select_all') }}
|
||||
</el-checkbox>
|
||||
<el-checkbox-group
|
||||
v-model="checkedWorkspace"
|
||||
class="checkbox-group-block"
|
||||
@change="handleCheckedWorkspaceChange"
|
||||
>
|
||||
<el-checkbox
|
||||
v-for="space in workspaceWithKeywords"
|
||||
:key="space.id"
|
||||
:label="space.name"
|
||||
:value="space"
|
||||
>
|
||||
<div class="flex">
|
||||
<el-icon size="28">
|
||||
<avatar_personal></avatar_personal>
|
||||
</el-icon>
|
||||
<span class="ml-4"> {{ space.name }}</span>
|
||||
<span class="account">({{ space.account }})</span>
|
||||
</div>
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-16 w-full">
|
||||
<div class="flex-between mb-16">
|
||||
<span class="lighter">
|
||||
{{ $t('workspace.selected_2_people', { msg: checkedWorkspace.length }) }}
|
||||
</span>
|
||||
|
||||
<el-button text @click="clearWorkspaceAll">
|
||||
{{ $t('workspace.clear') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div v-for="ele in checkedWorkspace" :key="ele.name" class="flex-between">
|
||||
<div class="flex align-center">
|
||||
<el-icon size="28">
|
||||
<avatar_personal></avatar_personal>
|
||||
</el-icon>
|
||||
<span class="ml-4 lighter">{{ ele.name }}</span>
|
||||
<span class="account">({{ ele.account }})</span>
|
||||
</div>
|
||||
<el-button text>
|
||||
<el-icon size="16" @click="clearWorkspace(ele)"><Close /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import { workspaceUserList } from '@/api/workspace'
|
||||
import avatar_personal from '@/assets/svg/avatar_personal.svg'
|
||||
import Close from '@/assets/svg/icon_close_outlined_w.svg'
|
||||
import Search from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import type { CheckboxValueType } from 'element-plus-secondary'
|
||||
const checkAll = ref(false)
|
||||
const isIndeterminate = ref(false)
|
||||
const checkedWorkspace = ref<any[]>([])
|
||||
const workspace = ref<any[]>([])
|
||||
const search = ref('')
|
||||
const loading = ref(false)
|
||||
const centerDialogVisible = ref(false)
|
||||
|
||||
const workspaceWithKeywords = computed(() => {
|
||||
return workspace.value.filter((ele: any) => (ele.name as string).includes(search.value))
|
||||
})
|
||||
const handleCheckAllChange = (val: CheckboxValueType) => {
|
||||
checkedWorkspace.value = val ? workspace.value : []
|
||||
isIndeterminate.value = false
|
||||
if (!val) {
|
||||
clearWorkspaceAll()
|
||||
}
|
||||
}
|
||||
const handleCheckedWorkspaceChange = (value: CheckboxValueType[]) => {
|
||||
const checkedCount = value.length
|
||||
checkAll.value = checkedCount === workspace.value.length
|
||||
isIndeterminate.value = checkedCount > 0 && checkedCount < workspace.value.length
|
||||
}
|
||||
|
||||
const open = async () => {
|
||||
loading.value = true
|
||||
checkedWorkspace.value = []
|
||||
checkAll.value = false
|
||||
isIndeterminate.value = false
|
||||
const systemWorkspaceList = await workspaceUserList({}, 1, 1000)
|
||||
workspace.value = systemWorkspaceList.items.filter((ele: any) => ele.weight !== 1) as any
|
||||
loading.value = false
|
||||
centerDialogVisible.value = true
|
||||
}
|
||||
|
||||
const clearWorkspace = (val: any) => {
|
||||
checkedWorkspace.value = checkedWorkspace.value.filter((ele: any) => ele.id !== val.id)
|
||||
}
|
||||
|
||||
const clearWorkspaceAll = () => {
|
||||
checkedWorkspace.value = []
|
||||
handleCheckedWorkspaceChange([])
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open,
|
||||
checkedWorkspace,
|
||||
})
|
||||
</script>
|
||||
<style lang="less">
|
||||
.select-user_permission {
|
||||
.mb-8 {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.mt-16 {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.p-16 {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.lighter {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.lighter-bold {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.checkbox-group-block {
|
||||
.ed-checkbox,
|
||||
.ed-checkbox__label,
|
||||
.flex {
|
||||
width: 100%;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
align-items: center;
|
||||
.account {
|
||||
color: #8f959e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.border {
|
||||
border: 1px solid #dee0e3;
|
||||
}
|
||||
|
||||
.w-full {
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
|
||||
.flex-between {
|
||||
height: 44px;
|
||||
}
|
||||
}
|
||||
|
||||
.mt-8 {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.max-height_workspace {
|
||||
max-height: calc(100% - 24px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.align-center {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-between {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.ml-4 {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.border-r {
|
||||
border-right: 1px solid #dee0e3;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,249 @@
|
||||
<script lang="ts">
|
||||
import icon_down_outlined from '@/assets/svg/arrow-down.svg'
|
||||
import icon_close_outlined_w from '@/assets/svg/icon_close_outlined_12.svg'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
export default {
|
||||
name: 'LogicRelation',
|
||||
}
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { type PropType, computed, toRefs } from 'vue'
|
||||
import FilterFiled from './FilterFiled.vue'
|
||||
import type { Item } from './FilterFiled.vue'
|
||||
export type Logic = 'or' | 'and'
|
||||
export type Relation = {
|
||||
child?: Relation[]
|
||||
logic: Logic
|
||||
x: number
|
||||
} & Item
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps({
|
||||
relationList: {
|
||||
type: Array as PropType<Relation[]>,
|
||||
default: () => [],
|
||||
},
|
||||
x: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
logic: {
|
||||
type: String as PropType<Logic>,
|
||||
default: 'or',
|
||||
},
|
||||
})
|
||||
|
||||
const marginLeft = computed(() => {
|
||||
return {
|
||||
marginLeft: props.x ? '20px' : 0,
|
||||
}
|
||||
})
|
||||
|
||||
const emits = defineEmits([
|
||||
'addCondReal',
|
||||
'changeAndOrDfs',
|
||||
'update:logic',
|
||||
'removeRelationList',
|
||||
'del',
|
||||
])
|
||||
|
||||
const { relationList } = toRefs(props)
|
||||
|
||||
const handleCommand = (type: any) => {
|
||||
emits('update:logic', type)
|
||||
emits('changeAndOrDfs', type)
|
||||
}
|
||||
|
||||
const removeRelationList = (index: any) => {
|
||||
relationList.value.splice(index, 1)
|
||||
}
|
||||
const addCondReal = (type: any) => {
|
||||
emits('addCondReal', type, props.logic === 'or' ? 'and' : 'or')
|
||||
}
|
||||
const add = (type: any, child: any, logic: any) => {
|
||||
child.push(
|
||||
type === 'condition'
|
||||
? {
|
||||
field_id: '',
|
||||
value: '',
|
||||
enum_value: '',
|
||||
term: '',
|
||||
filter_type: 'logic',
|
||||
name: '',
|
||||
}
|
||||
: { child: [], logic }
|
||||
)
|
||||
}
|
||||
const del = (index: any, child: any) => {
|
||||
child.splice(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="logic" :style="marginLeft">
|
||||
<div class="logic-left">
|
||||
<div class="operate-title">
|
||||
<span v-if="x" class="mrg-title">
|
||||
{{ logic === 'or' ? 'OR' : 'AND' }}
|
||||
</span>
|
||||
<el-dropdown v-else trigger="click" @command="handleCommand">
|
||||
<span class="mrg-title">
|
||||
{{ logic === 'or' ? 'OR' : 'AND' }}
|
||||
<el-icon size="12">
|
||||
<icon_down_outlined />
|
||||
</el-icon>
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item command="and">AND</el-dropdown-item>
|
||||
<el-dropdown-item command="or">OR</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
<span v-if="x" class="operate-icon">
|
||||
<el-icon size="12" @click="emits('removeRelationList')">
|
||||
<icon_close_outlined_w />
|
||||
</el-icon>
|
||||
</span>
|
||||
</div>
|
||||
<div class="logic-right">
|
||||
<template v-for="(item, index) in relationList" :key="index">
|
||||
<logic-relation
|
||||
v-if="item.child"
|
||||
:x="item.x"
|
||||
:logic="item.logic"
|
||||
:relation-list="item.child"
|
||||
@del="(idx) => del(idx, item.child)"
|
||||
@add-cond-real="(type, logic) => add(type, item.child, logic)"
|
||||
@remove-relation-list="removeRelationList(index)"
|
||||
>
|
||||
</logic-relation>
|
||||
<filter-filed v-else :item="item" :index="index" @del="emits('del', index)"></filter-filed>
|
||||
</template>
|
||||
<div class="logic-right-add">
|
||||
<button class="operand-btn" @click="addCondReal('condition')">
|
||||
<el-icon style="margin-right: 4px" size="16">
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</el-icon>
|
||||
{{ t('permission.add_conditions') }}
|
||||
</button>
|
||||
<button v-if="x < 2" class="operand-btn" @click="addCondReal('relation')">
|
||||
<el-icon style="margin-right: 4px" size="16">
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</el-icon>
|
||||
{{ t('permission.add_relationships') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.logic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
width: 100%;
|
||||
|
||||
.logic-left {
|
||||
box-sizing: border-box;
|
||||
width: 48px;
|
||||
display: flex;
|
||||
position: relative;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
background: #fff;
|
||||
width: 48px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
&::after {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #1f23291a;
|
||||
z-index: 1;
|
||||
border-radius: 4px;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.operate-title {
|
||||
word-wrap: break-word;
|
||||
box-sizing: border-box;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
font-size: 12px;
|
||||
display: inline-block;
|
||||
white-space: nowrap;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 20px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 20px;
|
||||
color: #1f2329;
|
||||
|
||||
.mrg-title {
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: flex;
|
||||
height: 20px;
|
||||
font-size: 12px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.operate-icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.mrg-title {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.operate-icon {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.logic-right-add {
|
||||
display: flex;
|
||||
height: 41.4px;
|
||||
align-items: center;
|
||||
padding-left: 26px;
|
||||
|
||||
.operand-btn {
|
||||
box-sizing: border-box;
|
||||
font-weight: 400;
|
||||
text-align: center;
|
||||
outline: 0;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
height: 32px;
|
||||
padding: 0 10px;
|
||||
margin-right: 10px;
|
||||
font-size: 14px;
|
||||
color: #1cba90;
|
||||
background: #fff;
|
||||
border: 1px solid #1cba90;
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,224 @@
|
||||
<script lang="ts" setup>
|
||||
import icon_deleteTrash_outlined from '@/assets/svg/icon_delete.svg'
|
||||
import { ref, inject, computed, onBeforeMount, toRefs, type Ref } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { allOptions } from '../options'
|
||||
export interface Item {
|
||||
term: string
|
||||
field_id: string
|
||||
filter_type: string
|
||||
enum_value: string
|
||||
name: string
|
||||
value: any
|
||||
}
|
||||
|
||||
export interface sysVariable {
|
||||
label: string
|
||||
value: string
|
||||
type: string
|
||||
}
|
||||
|
||||
type Props = {
|
||||
index: number
|
||||
item: Item
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
index: 0,
|
||||
item: () => ({
|
||||
term: '',
|
||||
field_id: '',
|
||||
filter_type: '',
|
||||
enum_value: '',
|
||||
name: '',
|
||||
value: null,
|
||||
}),
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const showDel = ref(false)
|
||||
const keywords = ref('')
|
||||
const activeName = ref({})
|
||||
const checklist = ref<string[]>([])
|
||||
const filterList = ref<any[]>([])
|
||||
|
||||
const { item } = toRefs(props)
|
||||
|
||||
const filedList = inject('filedList') as Ref<any[]>
|
||||
|
||||
const computedWidth = computed(() => {
|
||||
const { field_id } = item.value
|
||||
return {
|
||||
width: !field_id ? '270px' : '670px',
|
||||
}
|
||||
})
|
||||
|
||||
const operators = computed(() => {
|
||||
return allOptions
|
||||
})
|
||||
|
||||
const computedFiledList = computed<any[]>(() => {
|
||||
return filedList.value || []
|
||||
})
|
||||
|
||||
const dimensions = computed(() => {
|
||||
if (!keywords.value) return computedFiledList.value
|
||||
return computedFiledList.value.filter((ele) => ele.name.includes(keywords.value))
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
initNameEnumName()
|
||||
filterListInit()
|
||||
})
|
||||
|
||||
const initNameEnumName = () => {
|
||||
const { name, enum_value, field_id } = item.value
|
||||
dimensions.value.forEach((ele) => {
|
||||
if (+ele.id === +field_id) {
|
||||
activeName.value = ele
|
||||
}
|
||||
})
|
||||
const arr = enum_value.trim() ? enum_value.split(',') : []
|
||||
if (!name && field_id) {
|
||||
checklist.value = arr
|
||||
}
|
||||
if (!name && !field_id) return
|
||||
initEnumOptions()
|
||||
checklist.value = arr
|
||||
}
|
||||
|
||||
const filterTypeChange = () => {
|
||||
item.value.term = ''
|
||||
item.value.value = null
|
||||
initEnumOptions()
|
||||
}
|
||||
const initEnumOptions = () => {
|
||||
console.log('initEnumOptions')
|
||||
}
|
||||
|
||||
const selectItem = ({ field_name, id }: any) => {
|
||||
Object.assign(item.value, {
|
||||
field_id: id,
|
||||
name: field_name,
|
||||
filter_type: 'logic',
|
||||
value: '',
|
||||
term: '',
|
||||
})
|
||||
filterListInit()
|
||||
checklist.value = []
|
||||
}
|
||||
|
||||
const filterListInit = () => {
|
||||
filterList.value = [
|
||||
{
|
||||
value: 'logic',
|
||||
label: t('permission.conditional_filtering'),
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
const emits = defineEmits(['update:item', 'del'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="white-nowrap">
|
||||
<div
|
||||
class="filed"
|
||||
:style="computedWidth"
|
||||
@mouseover="showDel = true"
|
||||
@mouseleave="showDel = false"
|
||||
>
|
||||
<el-select
|
||||
v-model="activeName"
|
||||
value-key="id"
|
||||
:placeholder="$t('permission.conditional_filtering')"
|
||||
style="width: 200px"
|
||||
@change="selectItem"
|
||||
>
|
||||
<el-option v-for="ele in dimensions" :key="ele.id" :label="ele.field_name" :value="ele" />
|
||||
</el-select>
|
||||
<template v-if="item.field_id">
|
||||
<el-select
|
||||
v-model="item.filter_type"
|
||||
style="width: 120px; margin-left: 8px"
|
||||
:placeholder="$t('permission.conditional_filtering')"
|
||||
@change="filterTypeChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="ele in filterList"
|
||||
:key="ele.value"
|
||||
:label="ele.label"
|
||||
:value="ele.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input
|
||||
v-model="item.value"
|
||||
style="max-width: 280px; margin-left: 8px"
|
||||
:placeholder="$t('datasource.please_enter')"
|
||||
class="input-with-select"
|
||||
>
|
||||
<template #prepend>
|
||||
<el-select
|
||||
v-model="item.term"
|
||||
style="width: 75px"
|
||||
:placeholder="t('datasource.Please_select')"
|
||||
>
|
||||
<el-option
|
||||
v-for="ele in operators"
|
||||
:key="ele.value"
|
||||
:label="t(ele.label)"
|
||||
:value="ele.value"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</template>
|
||||
<el-icon v-if="showDel" class="font16" @click="emits('del')">
|
||||
<icon_deleteTrash_outlined />
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.white-nowrap {
|
||||
white-space: nowrap;
|
||||
}
|
||||
.filed {
|
||||
height: 41.4px;
|
||||
padding: 1px 3px 1px 0;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 20px;
|
||||
min-width: 200px;
|
||||
justify-content: left;
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
|
||||
.filed-title {
|
||||
word-wrap: break-word;
|
||||
line-height: 28px;
|
||||
color: #7e7e7e;
|
||||
font-size: 14px;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
min-width: 50px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.font16 {
|
||||
font-size: 16px;
|
||||
margin: 0 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:deep(.ed-input-group__prepend) {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,313 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import AuthTree from './AuthTree.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const errorMessage = ref('')
|
||||
const logic = ref<'or' | 'and'>('or')
|
||||
const relationList = ref<any[]>([])
|
||||
|
||||
const svgRealinePath = computed(() => {
|
||||
const lg = relationList.value.length
|
||||
let a = { x: 0, y: 0, child: relationList.value }
|
||||
a.y = Math.floor(dfsXY(a, 0) / 2)
|
||||
if (!lg) return ''
|
||||
let path = calculateDepth(a)
|
||||
return path
|
||||
})
|
||||
|
||||
const svgDashinePath = computed(() => {
|
||||
const lg = relationList.value.length
|
||||
let a = { x: 0, y: 0, child: relationList.value }
|
||||
a.y = Math.floor(dfsXY(a, 0) / 2)
|
||||
if (!lg) return `M48 20 L68 20`
|
||||
let path = calculateDepthDash(a)
|
||||
return path
|
||||
})
|
||||
|
||||
const init = (expressionTree: any) => {
|
||||
const { logic: lg = 'or', items = [] } = expressionTree
|
||||
logic.value = lg
|
||||
relationList.value = dfsInit(items)
|
||||
}
|
||||
const submit = () => {
|
||||
errorMessage.value = ''
|
||||
emits('save', {
|
||||
logic: logic.value,
|
||||
items: dfsSubmit(relationList.value),
|
||||
errorMessage: errorMessage.value,
|
||||
})
|
||||
}
|
||||
const errorDetected = ({ filter_type, field_id, term, value }: any) => {
|
||||
if (!field_id) {
|
||||
errorMessage.value = t('permission.cannot_be_empty_')
|
||||
return
|
||||
}
|
||||
if (filter_type === 'logic') {
|
||||
if (!term) {
|
||||
errorMessage.value = t('permission.cannot_be_empty_de_ruler')
|
||||
return
|
||||
}
|
||||
if (!term.includes('null') && !term.includes('empty') && value === '') {
|
||||
errorMessage.value = t('permission.filter_value_can_null')
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
const dfsInit = (arr: any[]) => {
|
||||
const elementList: any[] = []
|
||||
arr.forEach((ele: any) => {
|
||||
const { subTree } = ele
|
||||
if (subTree) {
|
||||
const { items, logic } = subTree
|
||||
const child = dfsInit(items)
|
||||
elementList.push({ logic, child })
|
||||
} else {
|
||||
const { enum_value, field_id, filter_type, term, value, field } = ele
|
||||
const { name } = field || {}
|
||||
elementList.push({
|
||||
enum_value: enum_value.join(','),
|
||||
field_id,
|
||||
filter_type,
|
||||
term,
|
||||
value,
|
||||
name,
|
||||
})
|
||||
}
|
||||
})
|
||||
return elementList
|
||||
}
|
||||
const dfsSubmit = (arr: any[]) => {
|
||||
const items: any[] = []
|
||||
arr.forEach((ele) => {
|
||||
const { child = [] } = ele
|
||||
if (child.length) {
|
||||
const { logic } = ele
|
||||
const subTree = dfsSubmit(child)
|
||||
items.push({
|
||||
enum_value: [],
|
||||
field_id: '',
|
||||
filter_type: '',
|
||||
term: '',
|
||||
type: 'tree',
|
||||
value: '',
|
||||
subTree: { logic, items: subTree },
|
||||
})
|
||||
} else {
|
||||
const { enum_value, field_id, filter_type, term, value, name } = ele
|
||||
errorDetected({ enum_value, field_id, filter_type, term, value, name })
|
||||
if (field_id) {
|
||||
items.push({
|
||||
enum_value: enum_value ? enum_value.split(',') : [],
|
||||
field_id,
|
||||
filter_type,
|
||||
term,
|
||||
value,
|
||||
type: 'item',
|
||||
subTree: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
return items
|
||||
}
|
||||
const removeRelationList = () => {
|
||||
relationList.value = []
|
||||
}
|
||||
const getY: any = (arr: any[]) => {
|
||||
const [a] = arr
|
||||
if (a.child?.length) {
|
||||
return getY(a.child)
|
||||
}
|
||||
return a.y
|
||||
}
|
||||
const calculateDepthDash = (obj: any) => {
|
||||
const lg = obj.child?.length
|
||||
let path = ''
|
||||
if (!lg && Array.isArray(obj.child)) {
|
||||
const { x, y } = obj
|
||||
path += `M${48 + x * 68} ${y * 41.4 + 20} L${88 + x * 68} ${y * 41.4 + 20}`
|
||||
} else if (obj.child?.length) {
|
||||
let y = Math.max(dfsY(obj, 0), dfs(obj.child, 0) + getY(obj.child) - 1)
|
||||
let parent = (dfs(obj.child, 0) * 41.4) / 2 + (getY(obj.child) || 0) * 41.4
|
||||
const { x } = obj
|
||||
path += `M${24 + x * 68} ${parent} L${24 + x * 68} ${y * 41.4 + 20} L${
|
||||
64 + x * 68
|
||||
} ${y * 41.4 + 20}`
|
||||
obj.child.forEach((item: any) => {
|
||||
path += calculateDepthDash(item)
|
||||
})
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
const calculateDepth = (obj: any) => {
|
||||
const lg = obj.child.length
|
||||
if (!lg) return ''
|
||||
let path = ''
|
||||
const { x: depth, y } = obj
|
||||
obj.child.forEach((item: any, index: any) => {
|
||||
const { y: sibingLg, z } = item
|
||||
if (item.child?.length) {
|
||||
let parent = (dfs(obj.child, 0) * 41.4) / 2 + (getY(obj.child) || 0) * 41.4
|
||||
let children = (dfs(item.child, 0) * 41.4) / 2 + getY(item.child) * 41.4
|
||||
let path1 = 0
|
||||
let path2 = 0
|
||||
if (parent < children) {
|
||||
path1 = parent
|
||||
path2 = children
|
||||
} else {
|
||||
;[path1, path2] = [children, parent]
|
||||
}
|
||||
if (y >= sibingLg) {
|
||||
path1 = parent
|
||||
path2 = children
|
||||
}
|
||||
path += `M${24 + depth * 68} ${path1} L${24 + depth * 68} ${path2} L${
|
||||
68 + depth * 68
|
||||
} ${path2}`
|
||||
// path += a;
|
||||
path += calculateDepth(item)
|
||||
}
|
||||
if (!item.child?.length) {
|
||||
if (sibingLg >= y) {
|
||||
path += `M${24 + depth * 68} ${y * 40} L${24 + depth * 68} ${
|
||||
(sibingLg + 1) * 41.4 - 20.69921875
|
||||
} L${68 + depth * 68} ${(sibingLg + 1) * 41.4 - 20.69921875}`
|
||||
} else {
|
||||
path += `M${24 + depth * 68} ${
|
||||
(sibingLg +
|
||||
(lg === 1 && index === 0 ? 0 : 1) +
|
||||
(obj.child[index + 1]?.child?.length ? y - sibingLg - 1 : 0)) *
|
||||
41.4 +
|
||||
20 +
|
||||
(lg === 1 && index === 0 ? 26 : 0)
|
||||
} L${24 + depth * 68} ${
|
||||
(sibingLg + 1) * 41.4 - 20.69921875 - (lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||
} L${68 + depth * 68} ${
|
||||
(sibingLg + 1) * 41.4 - 20.69921875 - (lg === 1 && index === 0 ? (z || 0) * 1.4 : 0)
|
||||
}`
|
||||
}
|
||||
}
|
||||
})
|
||||
return path
|
||||
}
|
||||
const changeAndOrDfs = (arr: any, logic: any) => {
|
||||
arr.forEach((ele: any) => {
|
||||
if (ele.child) {
|
||||
ele.logic = logic === 'and' ? 'or' : 'and'
|
||||
changeAndOrDfs(ele.child, ele.logic)
|
||||
}
|
||||
})
|
||||
}
|
||||
const dfs = (arr: any[], count: any) => {
|
||||
arr.forEach((ele) => {
|
||||
if (ele.child?.length) {
|
||||
count = dfs(ele.child, count)
|
||||
} else {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
count += 1
|
||||
return count
|
||||
}
|
||||
const dfsY = (obj: any, count: any) => {
|
||||
obj.child.forEach((ele: any) => {
|
||||
if (ele.child?.length) {
|
||||
count = dfsY(ele, count)
|
||||
} else {
|
||||
count = Math.max(count, ele.y, obj.y)
|
||||
}
|
||||
})
|
||||
return count
|
||||
}
|
||||
const dfsXY = (obj: any, count: any) => {
|
||||
obj.child.forEach((ele: any) => {
|
||||
ele.x = obj.x + 1
|
||||
if (ele.child?.length) {
|
||||
let l = dfs(ele.child, 0)
|
||||
ele.y = Math.floor(l / 2) + count
|
||||
count = dfsXY(ele, count)
|
||||
} else {
|
||||
count += 1
|
||||
ele.y = count - 1
|
||||
}
|
||||
})
|
||||
count += 1
|
||||
return count
|
||||
}
|
||||
const addCondReal = (type: any, logic: any) => {
|
||||
relationList.value.push(
|
||||
type === 'condition'
|
||||
? {
|
||||
field_id: '',
|
||||
value: '',
|
||||
enum_value: '',
|
||||
term: '',
|
||||
filter_type: 'logic',
|
||||
name: '',
|
||||
}
|
||||
: { child: [], logic }
|
||||
)
|
||||
}
|
||||
const del = (index: any) => {
|
||||
relationList.value.splice(index, 1)
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
init,
|
||||
submit,
|
||||
})
|
||||
const emits = defineEmits(['save'])
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="rowAuth">
|
||||
<auth-tree
|
||||
v-model:logic="logic"
|
||||
:relation-list="relationList"
|
||||
@del="(idx) => del(idx)"
|
||||
@add-cond-real="addCondReal"
|
||||
@remove-relation-list="removeRelationList"
|
||||
@change-and-or-dfs="(type) => changeAndOrDfs(relationList, type)"
|
||||
/>
|
||||
<svg width="388" height="100%" class="real-line">
|
||||
<path
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="round"
|
||||
:d="svgRealinePath"
|
||||
fill="none"
|
||||
stroke="#D9DCDF"
|
||||
stroke-width="0.5"
|
||||
></path>
|
||||
</svg>
|
||||
<svg width="388" height="100%" class="dash-line">
|
||||
<path
|
||||
stroke-linejoin="round"
|
||||
stroke-linecap="round"
|
||||
:d="svgDashinePath"
|
||||
fill="none"
|
||||
stroke="#D9DCDF"
|
||||
stroke-width="0.5"
|
||||
stroke-dasharray="4,4"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.rowAuth {
|
||||
font-family: Avenir, Helvetica, Arial, sans-serif;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
position: relative;
|
||||
}
|
||||
.real-line,
|
||||
.dash-line {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,18 @@
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed, reactive } from 'vue'
|
||||
import { ref, computed, reactive, provide, nextTick } from 'vue'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
import IconOpeEdit from '@/assets/svg/icon_edit_outlined.svg'
|
||||
import IconOpeDelete from '@/assets/svg/icon_delete.svg'
|
||||
import icon_close_outlined from '@/assets/svg/operate/ope-close.svg'
|
||||
import icon_down_outlined from '@/assets/svg/icon_down_outlined.svg'
|
||||
import Card from './Card.vue'
|
||||
|
||||
import SelectPermission from './SelectPermission.vue'
|
||||
import AuthTree from './auth-tree/RowAuth.vue'
|
||||
import { getList, savePermissions } from '@/api/permissions'
|
||||
import { datasourceApi } from '@/api/datasource'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
const keywords = ref('')
|
||||
@@ -18,38 +24,51 @@ const termFormRef = ref()
|
||||
const columnFormRef = ref()
|
||||
const drawerTitle = ref('')
|
||||
const dialogTitle = ref('')
|
||||
const tableData = ref<any[]>([])
|
||||
const ruleList = ref<any[]>([
|
||||
{
|
||||
id: 1,
|
||||
num: '10',
|
||||
type: '90',
|
||||
name: 'jkjkj',
|
||||
},
|
||||
])
|
||||
const form = reactive({
|
||||
name: '',
|
||||
const activeDs = ref({})
|
||||
const activeTable = ref({})
|
||||
const ruleList = ref<any[]>([])
|
||||
|
||||
const defaultPermission = {
|
||||
id: '',
|
||||
})
|
||||
const tableColumnData = ref<any[]>([])
|
||||
name: '',
|
||||
permissions: [],
|
||||
users: [],
|
||||
}
|
||||
const currentPermission = reactive<any>(cloneDeep(defaultPermission))
|
||||
|
||||
const searchColumn = ref('')
|
||||
|
||||
const columnForm = reactive({
|
||||
const isCreate = ref(false)
|
||||
const defaultForm = {
|
||||
name: '',
|
||||
id: '',
|
||||
dataTable: '',
|
||||
datasource: '',
|
||||
})
|
||||
|
||||
const options = ref<any[]>([])
|
||||
table_id: '',
|
||||
type: 'row',
|
||||
ds_id: '',
|
||||
table_name: '',
|
||||
ds_name: '',
|
||||
permissions: [] as any[],
|
||||
expression_tree: {},
|
||||
}
|
||||
const columnForm = reactive(cloneDeep(defaultForm))
|
||||
const selectPermissionRef = ref()
|
||||
const tableListOptions = ref<any[]>([])
|
||||
const fieldListOptions = ref<any[]>([])
|
||||
const dsListOptions = ref<any[]>([])
|
||||
const ruleListWithSearch = computed(() => {
|
||||
if (!keywords.value) return ruleList.value
|
||||
return ruleList.value.filter((ele) =>
|
||||
ele.name.toLowerCase().includes(keywords.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
const tableColumnData = computed<any[]>(() => {
|
||||
if (!searchColumn.value) return columnForm.permissions
|
||||
return columnForm.permissions.filter((ele) =>
|
||||
ele.field_name.toLowerCase().includes(searchColumn.value.toLowerCase())
|
||||
)
|
||||
})
|
||||
provide('filedList', fieldListOptions)
|
||||
const setDrawerTitle = () => {
|
||||
if (activeStep.value === 0) {
|
||||
if (activeStep.value === 0 && isCreate.value) {
|
||||
drawerTitle.value = t('permission.add_rule_group')
|
||||
} else {
|
||||
if (editRule.value === 1) {
|
||||
@@ -72,39 +91,194 @@ const userTypeList = [
|
||||
value: 0,
|
||||
},
|
||||
]
|
||||
|
||||
const ruleType = ref(0)
|
||||
const handleAddPermission = (val: any) => {
|
||||
ruleType.value = val
|
||||
Object.assign(columnForm, cloneDeep(defaultForm))
|
||||
if (val === 1) {
|
||||
handleRowPermission()
|
||||
handleRowPermission(null)
|
||||
} else {
|
||||
handleColumnPermission(null)
|
||||
}
|
||||
}
|
||||
const saveAuthTree = (val: any) => {
|
||||
if (val.errorMessage) {
|
||||
ElMessage.error(val.errorMessage)
|
||||
return
|
||||
}
|
||||
delete val.errorMessage
|
||||
columnForm.expression_tree = cloneDeep(val)
|
||||
const { expression_tree, table_id, ds_id, type, name, ds_name, table_name } = columnForm
|
||||
if (columnForm.id) {
|
||||
for (const key in currentPermission.permissions) {
|
||||
if (currentPermission.permissions[key].id === columnForm.id) {
|
||||
Object.assign(
|
||||
currentPermission.permissions[key],
|
||||
cloneDeep({
|
||||
expression_tree,
|
||||
table_id,
|
||||
ds_id,
|
||||
type,
|
||||
name,
|
||||
ds_name,
|
||||
table_name,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentPermission.permissions.push(
|
||||
cloneDeep({ expression_tree, table_id, ds_id, type, name, ds_name, table_name })
|
||||
)
|
||||
}
|
||||
dialogFormVisible.value = false
|
||||
}
|
||||
const getDsList = (row: any) => {
|
||||
activeDs.value = {}
|
||||
activeTable.value = {}
|
||||
datasourceApi
|
||||
.list()
|
||||
.then((res: any) => {
|
||||
dsListOptions.value = res || []
|
||||
if (!row?.ds_id) return
|
||||
dsListOptions.value.forEach((ele) => {
|
||||
if (ele.id === row.ds_id) {
|
||||
activeDs.value = ele
|
||||
}
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
if (!row && columnForm.type === 'row') {
|
||||
authTreeRef.value.init(columnForm.expression_tree)
|
||||
}
|
||||
})
|
||||
|
||||
const handleRowPermission = () => {
|
||||
console.log('handleRowPermission')
|
||||
if (row) {
|
||||
handleDsIdChange(row)
|
||||
handleEditeTable(row.table_id)
|
||||
}
|
||||
}
|
||||
const handleRowPermission = (row: any) => {
|
||||
columnForm.type = 'row'
|
||||
getDsList(row)
|
||||
if (row) {
|
||||
const { name, ds_id, table_id, tree, id, ds_name, table_name } = row
|
||||
Object.assign(columnForm, {
|
||||
id,
|
||||
name,
|
||||
ds_id,
|
||||
table_id,
|
||||
ds_name,
|
||||
table_name,
|
||||
expression_tree: tree,
|
||||
})
|
||||
}
|
||||
dialogFormVisible.value = true
|
||||
dialogTitle.value = row?.id
|
||||
? t('permission.edit_row_permission')
|
||||
: t('permission.add_row_permission')
|
||||
}
|
||||
const handleColumnPermission = (row: any) => {
|
||||
columnForm.type = 'column'
|
||||
getDsList(row)
|
||||
if (row) {
|
||||
const { name, ds_id, table_id, id, permission_list, ds_name, table_name } = row
|
||||
Object.assign(columnForm, {
|
||||
id,
|
||||
name,
|
||||
ds_id,
|
||||
ds_name,
|
||||
table_id,
|
||||
table_name,
|
||||
permissions: permission_list,
|
||||
})
|
||||
}
|
||||
dialogFormVisible.value = true
|
||||
dialogTitle.value = row?.id
|
||||
? t('permission.edit_column_permission')
|
||||
: t('permission.add_column_permission')
|
||||
}
|
||||
|
||||
const handleDsIdChange = (val: any) => {
|
||||
columnForm.ds_id = val.id
|
||||
columnForm.ds_name = val.name
|
||||
datasourceApi.tableList(val.id).then((res: any) => {
|
||||
tableListOptions.value = res || []
|
||||
if (!columnForm.table_id) return
|
||||
tableListOptions.value.forEach((ele) => {
|
||||
if (ele.id === columnForm.table_id) {
|
||||
activeTable.value = ele
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const handleTableIdChange = (val: any) => {
|
||||
columnForm.table_id = val.id
|
||||
columnForm.table_name = val.name
|
||||
datasourceApi.fieldList(val.id).then((res: any) => {
|
||||
fieldListOptions.value = res || []
|
||||
if (columnForm.type === 'row') return
|
||||
columnForm.permissions = fieldListOptions.value.map((ele) => {
|
||||
const { id, field_name, field_comment } = ele
|
||||
return { field_id: id, field_name, field_comment, enable: true }
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const handleEditeTable = (val: any) => {
|
||||
datasourceApi
|
||||
.fieldList(val)
|
||||
.then((res: any) => {
|
||||
fieldListOptions.value = res || []
|
||||
if (columnForm.type === 'row') return
|
||||
const enableMap = columnForm.permissions.reduce((pre, next) => {
|
||||
pre[next.field_id] = next.enable
|
||||
return pre
|
||||
}, {})
|
||||
columnForm.permissions = fieldListOptions.value.map((ele) => {
|
||||
const { id, field_name, field_comment } = ele
|
||||
return { field_id: id, field_name, field_comment, enable: enableMap[id] ?? false }
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
authTreeRef.value.init(columnForm.expression_tree)
|
||||
})
|
||||
}
|
||||
const beforeClose = () => {
|
||||
ruleConfigvVisible.value = false
|
||||
activeStep.value = 0
|
||||
isCreate.value = false
|
||||
}
|
||||
const handleSearch = () => {}
|
||||
const editHandler = (row: any) => {
|
||||
const handleSearch = () => {
|
||||
getList().then((res: any) => {
|
||||
ruleList.value = res || []
|
||||
})
|
||||
}
|
||||
handleSearch()
|
||||
const addHandler = () => {
|
||||
editRule.value = 0
|
||||
setDrawerTitle()
|
||||
isCreate.value = true
|
||||
Object.assign(currentPermission, cloneDeep(defaultPermission))
|
||||
ruleConfigvVisible.value = true
|
||||
console.log('row', row)
|
||||
}
|
||||
|
||||
const editForm = (row: any) => {
|
||||
if (row.type === 'row') {
|
||||
ruleType.value = 1
|
||||
handleRowPermission(row)
|
||||
} else {
|
||||
ruleType.value = 0
|
||||
handleColumnPermission(row)
|
||||
}
|
||||
}
|
||||
const handleEditRule = (row: any) => {
|
||||
editRule.value = 1
|
||||
isCreate.value = false
|
||||
setDrawerTitle()
|
||||
console.log(row)
|
||||
Object.assign(currentPermission, cloneDeep(row))
|
||||
ruleConfigvVisible.value = true
|
||||
}
|
||||
const deleteHandler = (row: any) => {
|
||||
console.log(row)
|
||||
@@ -128,8 +302,81 @@ const rules = {
|
||||
const closeForm = () => {
|
||||
dialogFormVisible.value = false
|
||||
}
|
||||
const authTreeRef = ref()
|
||||
const saveHandler = () => {
|
||||
columnFormRef.value.validate((res: any) => {
|
||||
if (res) {
|
||||
if (columnForm.type === 'row') {
|
||||
authTreeRef.value.submit()
|
||||
} else {
|
||||
const { permissions, table_id, ds_id, type, name, ds_name, table_name } = columnForm
|
||||
if (columnForm.id) {
|
||||
for (const key in currentPermission.permissions) {
|
||||
if (currentPermission.permissions[key].id === columnForm.id) {
|
||||
Object.assign(
|
||||
currentPermission.permissions[key],
|
||||
cloneDeep({
|
||||
permissions,
|
||||
table_id,
|
||||
ds_id,
|
||||
type,
|
||||
name,
|
||||
ds_name,
|
||||
table_name,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentPermission.permissions.push(
|
||||
cloneDeep({ permissions, table_id, ds_id, type, name, ds_name, table_name })
|
||||
)
|
||||
}
|
||||
}
|
||||
dialogFormVisible.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
const preview = () => {}
|
||||
const next = () => {
|
||||
activeStep.value = 1
|
||||
nextTick(() => {
|
||||
selectPermissionRef.value.open()
|
||||
})
|
||||
}
|
||||
const savePermission = () => {
|
||||
// termFormRef.value.validate((res: any) => {
|
||||
// if (res) {
|
||||
|
||||
const saveHandler = () => {}
|
||||
// }
|
||||
// })
|
||||
|
||||
const { id, name, permissions } = currentPermission
|
||||
const permissionsObj = permissions.map((ele: any) => {
|
||||
return {
|
||||
...cloneDeep(ele),
|
||||
permissions: JSON.stringify(ele.permissions || []),
|
||||
expression_tree: JSON.stringify(ele.expression_tree || {}),
|
||||
}
|
||||
})
|
||||
const obj = {
|
||||
id,
|
||||
name,
|
||||
permissions: permissionsObj,
|
||||
users: selectPermissionRef.value.checkedWorkspace.map((ele: any) => ele.id),
|
||||
}
|
||||
if (!id) {
|
||||
delete obj.id
|
||||
}
|
||||
savePermissions(obj).then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('common.save_success'),
|
||||
})
|
||||
ruleConfigvVisible.value = false
|
||||
handleSearch()
|
||||
})
|
||||
}
|
||||
|
||||
const columnRules = {
|
||||
name: [
|
||||
@@ -139,8 +386,7 @@ const columnRules = {
|
||||
trigger: 'blur',
|
||||
},
|
||||
],
|
||||
|
||||
dataTable: [
|
||||
table_id: [
|
||||
{
|
||||
required: true,
|
||||
message: t('datasource.please_enter') + t('common.empty') + t('permission.rule_group_name'),
|
||||
@@ -169,7 +415,7 @@ const columnRules = {
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<el-button type="primary" @click="editHandler(null)">
|
||||
<el-button type="primary" @click="addHandler()">
|
||||
<template #icon>
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</template>
|
||||
@@ -190,8 +436,8 @@ const columnRules = {
|
||||
:id="ele.id"
|
||||
:key="ele.id"
|
||||
:name="ele.name"
|
||||
:type="ele.type"
|
||||
:num="ele.num"
|
||||
:type="ele.users.length"
|
||||
:num="ele.permissions.length"
|
||||
@edit="handleEditRule(ele)"
|
||||
@del="deleteHandler(ele)"
|
||||
@set-user="setUser(ele)"
|
||||
@@ -223,14 +469,14 @@ const columnRules = {
|
||||
</el-icon>
|
||||
</template>
|
||||
|
||||
<div class="drawer-content">
|
||||
<div v-show="activeStep === 0" class="drawer-content">
|
||||
<div class="title">
|
||||
{{ $t('ds.form.base_info') }}
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
ref="termFormRef"
|
||||
:model="form"
|
||||
:model="currentPermission"
|
||||
label-width="180px"
|
||||
label-position="top"
|
||||
:rules="rules"
|
||||
@@ -238,7 +484,7 @@ const columnRules = {
|
||||
>
|
||||
<el-form-item prop="name" :label="t('permission.rule_group_name')">
|
||||
<el-input
|
||||
v-model="form.name"
|
||||
v-model="currentPermission.name"
|
||||
:placeholder="
|
||||
$t('datasource.please_enter') +
|
||||
$t('common.empty') +
|
||||
@@ -287,14 +533,27 @@ const columnRules = {
|
||||
<div class="table-content">
|
||||
<el-table
|
||||
:empty-text="$t('permission.no_rule')"
|
||||
:data="tableData"
|
||||
:data="currentPermission.permissions"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="name" :label="$t('permission.rule_name')" />
|
||||
<el-table-column prop="type" :label="$t('permission.type')" />
|
||||
<el-table-column prop="datasource" :label="$t('permission.data_source')" />
|
||||
<el-table-column prop="data_table" :label="$t('permission.data_table')" />
|
||||
<el-table-column fixed="right" width="150" :label="$t('ds.actions')">
|
||||
<el-table-column prop="type" :label="$t('permission.type')">
|
||||
<template #default="scope">
|
||||
{{
|
||||
scope.row.type === 'row'
|
||||
? $t('permission.row_permission')
|
||||
: $t('permission.column_permission')
|
||||
}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="ds_name" :label="$t('permission.data_source')" />
|
||||
<el-table-column prop="table_name" :label="$t('permission.data_table')" />
|
||||
<el-table-column
|
||||
class-name="actions-methods"
|
||||
fixed="right"
|
||||
width="80"
|
||||
:label="$t('ds.actions')"
|
||||
>
|
||||
<template #default="scope">
|
||||
<el-tooltip
|
||||
:offset="14"
|
||||
@@ -302,7 +561,7 @@ const columnRules = {
|
||||
:content="$t('datasource.edit')"
|
||||
placement="top"
|
||||
>
|
||||
<el-icon class="action-btn" size="16" @click="editHandler(scope.row)">
|
||||
<el-icon class="action-btn" size="16" @click="editForm(scope.row)">
|
||||
<IconOpeEdit></IconOpeEdit>
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
@@ -324,6 +583,21 @@ const columnRules = {
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div v-show="activeStep !== 0" class="select-permission_content">
|
||||
<SelectPermission ref="selectPermissionRef"></SelectPermission>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button secondary @click="beforeClose"> {{ $t('common.cancel') }} </el-button>
|
||||
<el-button v-if="activeStep === 1 && isCreate" secondary @click="preview">
|
||||
{{ t('ds.previous') }}
|
||||
</el-button>
|
||||
<el-button v-if="activeStep === 0 && isCreate" type="primary" @click="next">
|
||||
{{ t('common.next') }}
|
||||
</el-button>
|
||||
<el-button v-if="activeStep === 1" type="primary" @click="savePermission">
|
||||
{{ $t('common.save') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-drawer>
|
||||
|
||||
<el-drawer
|
||||
@@ -351,25 +625,39 @@ const columnRules = {
|
||||
autocomplete="off"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item prop="dataTable" :label="t('permission.data_table')">
|
||||
<el-form-item prop="table_id" :label="t('permission.data_table')">
|
||||
<el-select
|
||||
v-model="columnForm.datasource"
|
||||
v-model="activeDs"
|
||||
style="width: 416px"
|
||||
value-key="id"
|
||||
:placeholder="
|
||||
$t('datasource.Please_select') + $t('common.empty') + $t('permission.data_source')
|
||||
"
|
||||
@change="handleDsIdChange"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
|
||||
<el-option
|
||||
v-for="item in dsListOptions"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-model="columnForm.dataTable"
|
||||
v-model="activeTable"
|
||||
style="width: 416px; margin-left: auto"
|
||||
:disabled="!columnForm.datasource"
|
||||
:disabled="!columnForm.ds_id"
|
||||
value-key="id"
|
||||
:placeholder="
|
||||
$t('datasource.Please_select') + $t('common.empty') + $t('permission.data_table')
|
||||
"
|
||||
@change="handleTableIdChange"
|
||||
>
|
||||
<el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
|
||||
<el-option
|
||||
v-for="item in tableListOptions"
|
||||
:key="item.id"
|
||||
:label="item.table_name"
|
||||
:value="item"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('permission.set_rule')">
|
||||
@@ -377,6 +665,7 @@ const columnRules = {
|
||||
v-model="searchColumn"
|
||||
:placeholder="$t('permission.search_rule_group')"
|
||||
autocomplete="off"
|
||||
clearable
|
||||
><template #prefix>
|
||||
<el-icon>
|
||||
<icon_searchOutline_outlined />
|
||||
@@ -384,17 +673,18 @@ const columnRules = {
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="table-content">
|
||||
<AuthTree v-if="ruleType === 1" ref="authTreeRef" @save="saveAuthTree"></AuthTree>
|
||||
<div v-else class="table-content">
|
||||
<el-table
|
||||
:empty-text="$t('permission.no_fields_yet')"
|
||||
:data="tableColumnData"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-table-column prop="name" :label="$t('datasource.field_name')" />
|
||||
<el-table-column prop="type" :label="$t('datasource.field_notes')" />
|
||||
<el-table-column prop="field_name" :label="$t('datasource.field_name')" />
|
||||
<el-table-column prop="field_comment" :label="$t('datasource.field_notes')" />
|
||||
<el-table-column fixed="right" width="150" :label="$t('ds.actions')">
|
||||
<template #default="scope">
|
||||
<el-switch v-model="scope.row.checked" size="small" />
|
||||
<el-switch v-model="scope.row.enable" size="small" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -445,11 +735,14 @@ const columnRules = {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.select-permission_content,
|
||||
.drawer-content {
|
||||
width: 800px;
|
||||
margin: 0 auto;
|
||||
height: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
.add-btn:hover {
|
||||
.ed-icon {
|
||||
transform: rotate(180deg);
|
||||
@@ -466,6 +759,7 @@ const columnRules = {
|
||||
margin-top: 16px;
|
||||
border: 1px solid #1f232926;
|
||||
border-top: none;
|
||||
border-bottom: none;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
max-height: calc(100vh - 400px);
|
||||
@@ -473,6 +767,18 @@ const columnRules = {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.actions-methods {
|
||||
.cell {
|
||||
height: 24px;
|
||||
.action-btn {
|
||||
margin-top: 4px;
|
||||
&:nth-child(1) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ed-icon {
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
function formatEnum(ele: any) {
|
||||
return {
|
||||
value: ele,
|
||||
label: `permission.filter_${ele.replace(' ', '_')}`,
|
||||
}
|
||||
}
|
||||
|
||||
function toLine(name: any) {
|
||||
return name.replace(/([A-Z])/g, '_$1').toLowerCase()
|
||||
}
|
||||
const textEnum = [
|
||||
'eq',
|
||||
'not_eq',
|
||||
'in',
|
||||
'not in',
|
||||
'like',
|
||||
'not like',
|
||||
'null',
|
||||
'not_null',
|
||||
'empty',
|
||||
'not_empty',
|
||||
]
|
||||
const textOptions = textEnum.map(formatEnum)
|
||||
|
||||
const dateEnum = ['eq', 'not_eq', 'lt', 'gt', 'le', 'ge']
|
||||
const dateOptions = dateEnum.map(formatEnum)
|
||||
const allEnum = [...new Set(textEnum.concat(dateEnum))]
|
||||
const allOptions = allEnum.map(formatEnum)
|
||||
|
||||
const valueEnum = [...dateEnum]
|
||||
const valueOptions = valueEnum.map(formatEnum)
|
||||
|
||||
const sysParams = ['eq', 'not_eq', 'like', 'not like', 'in', 'not in']
|
||||
const textOptionsForSysParams = sysParams.map(formatEnum)
|
||||
|
||||
const sysParamsEnum = ['userId', 'userName', 'userEmail']
|
||||
|
||||
const sysParamsIlns = sysParamsEnum.map((_) => {
|
||||
return { value: `\${sysParams.${_}}`, label: `auth.sysParams_type.${toLine(_)}`, type: 'text' }
|
||||
})
|
||||
|
||||
const fieldEnums = ['text', 'time', 'value', 'value', 'value', 'location']
|
||||
|
||||
export {
|
||||
textOptions,
|
||||
dateOptions,
|
||||
valueOptions,
|
||||
textOptionsForSysParams,
|
||||
sysParamsIlns,
|
||||
fieldEnums,
|
||||
allOptions,
|
||||
}
|
||||
Reference in New Issue
Block a user