479 lines
14 KiB
Vue
479 lines
14 KiB
Vue
<template>
|
|
<el-drawer
|
|
v-model="drawerVisible"
|
|
:title="$t('views.system.resourceAuthorization.title')"
|
|
size="60%"
|
|
:append-to-body="true"
|
|
>
|
|
<div class="flex-between mb-16">
|
|
<el-button
|
|
type="primary"
|
|
:disabled="multipleSelection.length === 0"
|
|
@click="openMulConfigureDialog"
|
|
>{{ $t('views.system.resourceAuthorization.setting.configure') }}</el-button
|
|
>
|
|
|
|
<div class="flex-between complex-search">
|
|
<el-select
|
|
class="complex-search__left"
|
|
v-model="searchType"
|
|
style="width: 100px"
|
|
@change="search_type_change"
|
|
>
|
|
<el-option :label="$t('views.userManage.userForm.nick_name.label')" value="nick_name" />
|
|
<el-option :label="$t('views.login.loginForm.username.label')" value="username" />
|
|
<el-option :label="$t('views.model.modelForm.permissionType.label')" value="permission" />
|
|
</el-select>
|
|
<el-input
|
|
v-if="searchType === 'nick_name'"
|
|
v-model="searchForm.nick_name"
|
|
@change="searchHandle"
|
|
:placeholder="$t('common.search')"
|
|
style="width: 220px"
|
|
clearable
|
|
/>
|
|
<el-input
|
|
v-if="searchType === 'username'"
|
|
v-model="searchForm.username"
|
|
@change="searchHandle"
|
|
:placeholder="$t('common.search')"
|
|
style="width: 220px"
|
|
clearable
|
|
/>
|
|
|
|
<el-select
|
|
v-else-if="searchType === 'permission'"
|
|
v-model="searchForm.permission"
|
|
@change="searchHandle"
|
|
filterable
|
|
clearable
|
|
multiple
|
|
:reserve-keyword="false"
|
|
collapse-tags
|
|
collapse-tags-tooltip
|
|
style="width: 220px"
|
|
>
|
|
<template v-for="(item, index) in permissionOptions" :key="index">
|
|
<el-option :label="item.label" :value="item.value" />
|
|
</template>
|
|
</el-select>
|
|
</div>
|
|
</div>
|
|
|
|
<app-table
|
|
ref="multipleTableRef"
|
|
class="mt-16"
|
|
:data="permissionData"
|
|
:pagination-config="paginationConfig"
|
|
@sizeChange="handleSizeChange"
|
|
@changePage="getPermissionList"
|
|
@selection-change="handleSelectionChange"
|
|
:maxTableHeight="200"
|
|
:row-key="(row: any) => row.id"
|
|
v-loading="loading"
|
|
>
|
|
<el-table-column type="selection" width="55" :reserve-selection="true" />
|
|
<el-table-column
|
|
prop="nick_name"
|
|
:label="$t('views.userManage.userForm.nick_name.label')"
|
|
min-width="120"
|
|
show-overflow-tooltip
|
|
/>
|
|
<el-table-column
|
|
prop="username"
|
|
min-width="120"
|
|
show-overflow-tooltip
|
|
:label="$t('views.login.loginForm.username.label')"
|
|
/>
|
|
<!-- <el-table-column prop="role_name" :label="$t('views.role.member.role')" width="210">
|
|
<template #default="{ row }">
|
|
<el-popover :width="400">
|
|
<template #reference>
|
|
<TagGroup
|
|
class="cursor"
|
|
style="width: fit-content"
|
|
:tags="row.role_name"
|
|
tooltipDisabled
|
|
/>
|
|
</template>
|
|
<template #default>
|
|
<el-table :data="row.role_workspace">
|
|
<el-table-column prop="role" :label="$t('views.role.member.role')">
|
|
</el-table-column>
|
|
<el-table-column prop="workspace" :label="$t('views.workspace.title')">
|
|
</el-table-column>
|
|
</el-table>
|
|
</template>
|
|
</el-popover>
|
|
</template>
|
|
</el-table-column> -->
|
|
<el-table-column :label="$t('common.operation')" align="left" width="340">
|
|
<template #default="{ row }">
|
|
<el-radio-group
|
|
v-model="row.permission"
|
|
@change="(val: any) => permissionsHandle(val, row)"
|
|
>
|
|
<template v-for="(item, index) in getFolderPermissionOptions()" :key="index">
|
|
<el-radio :value="item.value" class="mr-16">{{ item.label }}</el-radio>
|
|
</template>
|
|
</el-radio-group>
|
|
</template>
|
|
</el-table-column>
|
|
</app-table>
|
|
<!-- 单个资源授权提示框 -->
|
|
<el-dialog
|
|
v-model="singleSelectDialogVisible"
|
|
:title="$t('views.system.resourceAuthorization.setting.effectiveResource')"
|
|
destroy-on-close
|
|
@close="closeSingleSelectDialog"
|
|
width="500px"
|
|
>
|
|
<el-radio-group v-model="authAllChildren" class="radio-block">
|
|
<el-radio :value="false">
|
|
<p class="color-text-primary lighter">
|
|
{{ $t('views.system.resourceAuthorization.setting.currentOnly') }}
|
|
</p>
|
|
</el-radio>
|
|
<el-radio :value="true">
|
|
<p class="color-text-primary lighter">
|
|
{{ $t('views.system.resourceAuthorization.setting.includeAll') }}
|
|
</p>
|
|
</el-radio>
|
|
</el-radio-group>
|
|
<template #footer>
|
|
<div class="dialog-footer mt-24">
|
|
<el-button @click="closeSingleSelectDialog">{{ $t('common.cancel') }}</el-button>
|
|
<el-button type="primary" @click="confirmSinglePermission">{{
|
|
$t('common.confirm')
|
|
}}</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
|
|
<!-- 批量配置 弹出层 -->
|
|
<el-dialog
|
|
v-model="dialogVisible"
|
|
:title="$t('views.system.resourceAuthorization.setting.configure')"
|
|
destroy-on-close
|
|
@close="closeDialog"
|
|
width="500px"
|
|
>
|
|
<el-radio-group v-model="radioPermission" class="radio-block">
|
|
<template v-for="(item, index) in getFolderPermissionOptions()" :key="index">
|
|
<el-radio :value="item.value" class="mr-16">
|
|
<p class="color-text-primary lighter">{{ item.label }}</p>
|
|
<el-text class="color-secondary lighter">{{ item.desc }}</el-text>
|
|
</el-radio>
|
|
</template>
|
|
</el-radio-group>
|
|
<!-- 如果是文件夹,显示子资源选项 -->
|
|
<div v-if="isFolder" class="mt-16">
|
|
<el-divider />
|
|
<div class="color-text-primary mb-8">
|
|
{{ $t('views.system.resourceAuthorization.setting.effectiveResource') }}
|
|
</div>
|
|
<el-radio-group v-model="batchAuthAllChildren" class="radio-block">
|
|
<el-radio :value="false">
|
|
<p class="color-text-primary lighter">
|
|
{{ $t('views.system.resourceAuthorization.setting.currentOnly') }}
|
|
</p>
|
|
</el-radio>
|
|
<el-radio :value="true">
|
|
<p class="color-text-primary lighter">
|
|
{{ $t('views.system.resourceAuthorization.setting.includeAll') }}
|
|
</p>
|
|
</el-radio>
|
|
</el-radio-group>
|
|
</div>
|
|
<template #footer>
|
|
<div class="dialog-footer mt-24">
|
|
<el-button @click="closeDialog"> {{ $t('common.cancel') }}</el-button>
|
|
<el-button type="primary" @click="submitDialog"> {{ $t('common.confirm') }}</el-button>
|
|
</div>
|
|
</template>
|
|
</el-dialog>
|
|
</el-drawer>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import { ref, onMounted, watch, computed, reactive } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import { getPermissionOptions } from '@/views/system/resource-authorization/constant'
|
|
import AuthorizationApi from '@/api/system/resource-authorization'
|
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
|
import { t } from '@/locales'
|
|
import permissionMap from '@/permission'
|
|
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
|
|
const route = useRoute()
|
|
import useStore from '@/stores'
|
|
import { hasPermission } from '@/utils/permission/index'
|
|
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
|
|
|
const { user } = useStore()
|
|
const props = defineProps<{
|
|
type: string
|
|
isFolder?: boolean
|
|
isRootFolder?: boolean
|
|
}>()
|
|
|
|
const apiType = computed(() => {
|
|
if (route.path.includes('resource-management')) {
|
|
return 'systemManage'
|
|
} else {
|
|
return 'workspace'
|
|
}
|
|
})
|
|
|
|
const folderType = computed(() => {
|
|
if (route.path.includes('application')) {
|
|
return 'application'
|
|
} else if (route.path.includes('knowledge')) {
|
|
return 'knowledge'
|
|
} else if (route.path.includes('tool')) {
|
|
return 'tool'
|
|
} else {
|
|
return 'application'
|
|
}
|
|
})
|
|
|
|
const permissionPrecise = computed(() => {
|
|
return permissionMap[folderType.value!]['workspace']
|
|
})
|
|
|
|
// 取出文件夹id
|
|
function getAllFolderIds(data: any) {
|
|
if (!data) return []
|
|
return [data.id, ...(data.children?.flatMap((child: any) => getAllFolderIds(child)) || [])]
|
|
}
|
|
|
|
const RESOURCE_PERMISSION_MAP = {
|
|
application:
|
|
PermissionConst.APPLICATION_RESOURCE_AUTHORIZATION.getWorkspacePermissionWorkspaceManageRole,
|
|
knowledge:
|
|
PermissionConst.KNOWLEDGE_RESOURCE_AUTHORIZATION.getWorkspacePermissionWorkspaceManageRole,
|
|
tool: PermissionConst.TOOL_RESOURCE_AUTHORIZATION.getWorkspacePermissionWorkspaceManageRole,
|
|
}
|
|
|
|
const resourceAuthorizationOfManager = computed(() => {
|
|
return RESOURCE_PERMISSION_MAP[folderType.value]
|
|
})
|
|
|
|
// 过滤没有Manage权限的文件夹ID
|
|
function filterHasPermissionFolderIds(folderIds: string[]) {
|
|
if (
|
|
hasPermission(
|
|
[RoleConst.WORKSPACE_MANAGE.getWorkspaceRole, resourceAuthorizationOfManager.value],
|
|
'OR',
|
|
)
|
|
) {
|
|
return folderIds
|
|
} else {
|
|
return folderIds.filter((id) => permissionPrecise.value.folderManage(id))
|
|
}
|
|
}
|
|
|
|
function confirmSinglePermission() {
|
|
if (!pendingPermissionChange.value) return
|
|
const { val, row } = pendingPermissionChange.value
|
|
let folderIds: string[] = []
|
|
if (authAllChildren.value && folderData.value) {
|
|
const allFolderIds = getAllFolderIds(folderData.value)
|
|
folderIds = filterHasPermissionFolderIds(allFolderIds)
|
|
}
|
|
const obj = [
|
|
{
|
|
user_id: row.id,
|
|
permission: val,
|
|
include_children: authAllChildren.value,
|
|
...(folderIds.length > 0 && { folder_ids: folderIds }),
|
|
},
|
|
]
|
|
submitPermissions(obj)
|
|
singleSelectDialogVisible.value = false
|
|
authAllChildren.value = false
|
|
pendingPermissionChange.value = null
|
|
getPermissionList()
|
|
}
|
|
|
|
const permissionOptionMap = computed(() => {
|
|
return {
|
|
rootFolder: getPermissionOptions(true, true),
|
|
folder: getPermissionOptions(true, false),
|
|
}
|
|
})
|
|
|
|
const getFolderPermissionOptions = () => {
|
|
if (props.isRootFolder) {
|
|
return permissionOptionMap.value.rootFolder
|
|
}
|
|
if (props.isFolder) {
|
|
return permissionOptionMap.value.folder
|
|
}
|
|
return getPermissionOptions(false, false)
|
|
}
|
|
|
|
const permissionOptions = computed(() => {
|
|
return getPermissionOptions()
|
|
})
|
|
const drawerVisible = ref(false)
|
|
const multipleTableRef = ref()
|
|
|
|
watch(drawerVisible, (bool) => {
|
|
if (!bool) {
|
|
targetId.value = ''
|
|
searchType.value = 'nick_name'
|
|
searchForm.value = { nick_name: '', username: '', permission: undefined }
|
|
permissionData.value = []
|
|
paginationConfig.current_page = 1
|
|
paginationConfig.total = 0
|
|
multipleSelection.value = []
|
|
multipleTableRef.value?.clearSelection()
|
|
}
|
|
})
|
|
|
|
const loading = ref(false)
|
|
const targetId = ref('')
|
|
const folderData = ref<any>(null)
|
|
const permissionData = ref<any[]>([])
|
|
const searchType = ref('nick_name')
|
|
const searchForm = ref<any>({
|
|
nick_name: '',
|
|
username: '',
|
|
permission: undefined,
|
|
})
|
|
|
|
const search_type_change = () => {
|
|
searchForm.value = { nick_name: '', username: '', permission: undefined }
|
|
}
|
|
|
|
const paginationConfig = reactive({
|
|
current_page: 1,
|
|
page_size: 20,
|
|
total: 0,
|
|
})
|
|
|
|
function handleSizeChange() {
|
|
paginationConfig.current_page = 1
|
|
getPermissionList()
|
|
}
|
|
function searchHandle() {
|
|
paginationConfig.current_page = 1
|
|
getPermissionList()
|
|
}
|
|
|
|
const multipleSelection = ref<any[]>([])
|
|
|
|
const handleSelectionChange = (val: any[]) => {
|
|
multipleSelection.value = val
|
|
}
|
|
|
|
const dialogVisible = ref(false)
|
|
const singleSelectDialogVisible = ref(false)
|
|
const pendingPermissionChange = ref<{ val: any; row: any } | null>(null)
|
|
const radioPermission = ref('')
|
|
const authAllChildren = ref(false)
|
|
function openMulConfigureDialog() {
|
|
if (multipleSelection.value.length === 0) {
|
|
return
|
|
}
|
|
dialogVisible.value = true
|
|
}
|
|
|
|
const batchAuthAllChildren = ref(false)
|
|
function submitDialog() {
|
|
if (multipleSelection.value.length === 0 || !radioPermission.value) {
|
|
return
|
|
}
|
|
let folderIds: string[] = []
|
|
if (props.isFolder && batchAuthAllChildren.value && folderData.value) {
|
|
const allFolderIds = getAllFolderIds(folderData.value)
|
|
folderIds = filterHasPermissionFolderIds(allFolderIds)
|
|
}
|
|
|
|
const obj = multipleSelection.value.map((item) => ({
|
|
user_id: item.id,
|
|
permission: radioPermission.value,
|
|
include_children: batchAuthAllChildren.value,
|
|
...(folderIds.length > 0 && { folder_ids: folderIds }),
|
|
}))
|
|
submitPermissions(obj)
|
|
closeDialog()
|
|
}
|
|
|
|
function closeSingleSelectDialog() {
|
|
singleSelectDialogVisible.value = false
|
|
authAllChildren.value = false
|
|
pendingPermissionChange.value = null
|
|
getPermissionList()
|
|
}
|
|
|
|
function closeDialog() {
|
|
dialogVisible.value = false
|
|
radioPermission.value = ''
|
|
batchAuthAllChildren.value = false
|
|
multipleSelection.value = []
|
|
multipleTableRef.value?.clearSelection()
|
|
}
|
|
|
|
function permissionsHandle(val: any, row: any) {
|
|
if (props.isFolder) {
|
|
singleSelectDialogVisible.value = true
|
|
pendingPermissionChange.value = { val, row }
|
|
return
|
|
}
|
|
const obj = [
|
|
{
|
|
user_id: row.id,
|
|
permission: val,
|
|
},
|
|
]
|
|
submitPermissions(obj)
|
|
}
|
|
|
|
function submitPermissions(obj: any) {
|
|
const workspaceId = user.getWorkspaceId() || 'default'
|
|
loadSharedApi({ type: 'resourceAuthorization', systemType: apiType.value })
|
|
.putResourceAuthorization(workspaceId, targetId.value, props.type, obj, loading)
|
|
.then(() => {
|
|
MsgSuccess(t('common.submitSuccess'))
|
|
getPermissionList()
|
|
})
|
|
}
|
|
const getPermissionList = () => {
|
|
const workspaceId = user.getWorkspaceId() || 'default'
|
|
const params: any = {}
|
|
if (searchForm.value[searchType.value]) {
|
|
params[searchType.value] = searchForm.value[searchType.value]
|
|
}
|
|
loadSharedApi({ type: 'resourceAuthorization', systemType: apiType.value })
|
|
.getResourceAuthorization(
|
|
workspaceId,
|
|
targetId.value,
|
|
props.type,
|
|
paginationConfig,
|
|
params,
|
|
loading,
|
|
)
|
|
.then((res: any) => {
|
|
permissionData.value =
|
|
res.data.records.map((item: any) => {
|
|
if (props.isRootFolder && item.permission === 'NOT_AUTH') {
|
|
return { ...item, permission: 'VIEW' }
|
|
}
|
|
return item
|
|
}) || []
|
|
paginationConfig.total = res.data.total || 0
|
|
})
|
|
}
|
|
|
|
const open = (id: string, folder_data?: any) => {
|
|
targetId.value = id
|
|
folderData.value = folder_data
|
|
drawerVisible.value = true
|
|
getPermissionList()
|
|
}
|
|
defineExpose({
|
|
open,
|
|
})
|
|
</script>
|
|
<style lang="scss" scoped></style>
|