UnisKB/ui/src/components/resource-authorization-drawer/index.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>