UnisKB/ui/src/components/resource-authorization-drawer/index.vue

520 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<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"
>
<div v-if="pendingPermissionChange" class="permission-confirm-info mb-16">
<div>{{ resourceTypeLabel }}{{ targetResourceName }}</div>
<div>
{{ $t('views.userManage.userForm.nick_name.label') }}{{
pendingPermissionChange.row?.nick_name || '-'
}}
</div>
<div>
{{ $t('views.login.loginForm.username.label') }}{{
pendingPermissionChange.row?.username || '-'
}}
</div>
<div>
{{ $t('views.model.modelForm.permissionType.label') }}{{
getPermissionLabel(pendingPermissionChange.val)
}}
</div>
</div>
<el-radio-group v-if="isFolder" 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>
<p v-else class="color-text-primary lighter">
{{ $t('common.confirm') }}
</p>
<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 = []
targetResource.value = null
folderData.value = null
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 targetResource = 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)
const resourceTypeLabelMap: Record<string, string> = {
APPLICATION: t('views.application.title'),
KNOWLEDGE: t('views.knowledge.title'),
TOOL: t('views.tool.title'),
MODEL: t('views.model.title'),
}
const resourceTypeLabel = computed(() => {
return props.isFolder
? '文件夹'
: resourceTypeLabelMap[props.type] || t('views.system.resourceAuthorization.title')
})
const targetResourceName = computed(() => {
return targetResource.value?.name || folderData.value?.name || targetId.value || '-'
})
const getPermissionLabel = (permission: string) => {
return (
getFolderPermissionOptions().find((item) => item.value === permission)?.label ||
permission ||
'-'
)
}
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) {
singleSelectDialogVisible.value = true
pendingPermissionChange.value = { val, row }
}
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, resource_data?: any) => {
targetId.value = id
folderData.value = props.isFolder ? resource_data : null
targetResource.value = resource_data || null
drawerVisible.value = true
getPermissionList()
}
defineExpose({
open,
})
</script>
<style lang="scss" scoped></style>