feat: System resource authorization function (#3861)

Co-authored-by: wangdan-fit2cloud <dan.wang@fit2cloud.com>
This commit is contained in:
shaohuzhang1 2025-08-15 16:03:03 +08:00 committed by GitHub
parent f78e24105f
commit c0b2aa3688
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 463 additions and 397 deletions

View File

@ -1,8 +1,7 @@
import { Permission } from '@/utils/permission/type'
import { Result } from '@/request/Result'
import { get, put, post, del } from '@/request/index'
import type { pageRequest } from '@/api/type/common'
import type { Ref } from 'vue'
import type { pageRequest } from '@/api/type/common'
const prefix = '/workspace'
/**
@ -13,11 +12,13 @@ const getResourceAuthorization: (
workspace_id: string,
user_id: string,
resource: string,
page: pageRequest,
params?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (workspace_id, user_id, resource, loading) => {
) => Promise<Result<any>> = (workspace_id, user_id, resource, page, params, loading) => {
return get(
`${prefix}/${workspace_id}/user_resource_permission/user/${user_id}/resource/${resource}`,
undefined,
`${prefix}/${workspace_id}/user_resource_permission/user/${user_id}/resource/${resource}/${page.current_page}/${page.page_size}`,
params,
loading,
)
}
@ -26,18 +27,12 @@ const getResourceAuthorization: (
*
* @param member_id
* @param {
"team_resource_permission_list": [
{
"auth_target_type": "KNOWLEDGE",
"target_id": "string",
"auth_type": "ROLE",
"permission": {
"VIEW": true,
"MANAGE": true,
"ROLE": true
}
}
]
[
{
"target_id": "string",
"permission": "NOT_AUTH"
}
]
}
*/
const putResourceAuthorization: (

View File

@ -22,7 +22,8 @@
:type="type" :send-message="sendMessage" :chat-management="ChatManagement"
:executionIsRightPanel="props.executionIsRightPanel"
@open-execution-detail="emit('openExecutionDetail', chatList[index])"
@openParagraph="emit('openParagraph', chatList[index])" @openParagraphDocument="
@openParagraph="emit('openParagraph', chatList[index])"
@openParagraphDocument="
(val: any) => emit('openParagraphDocument', chatList[index], val)
"></AnswerContent>
</template>

View File

@ -2,6 +2,7 @@ export enum AuthorizationEnum {
MANAGE = 'MANAGE',
VIEW = 'VIEW',
ROLE = 'ROLE',
NOT_AUTH = 'NOT_AUTH',
KNOWLEDGE = 'KNOWLEDGE',
APPLICATION = 'APPLICATION',
MODEL = 'MODEL',

View File

@ -109,18 +109,20 @@ export default {
enableSSL: 'Enable SSL (if the SMTP port is 465, you usually need to enable SSL)',
enableTLS: 'Enable TLS (if the SMTP port is 587, you usually need to enable TLS)',
},
resourceAuthorization: {
title: 'Resource Authorization',
member: 'Member',
permissionSetting: 'Permission Setting',
setting: {
management: 'management',
managementDesc: 'Can delete or modify this resource',
check: 'check',
authorization: 'authorization',
},
priority: {
label: 'Resource permission priority',
role: 'Role',
checkDesc: 'Can only view the resource',
role: 'User Role',
roleDesc: 'Authorize users based on their roles to access this resource',
notAuthorized: 'Not Authorized',
configure: 'Configure Permission',
},
},
resource_management: {

View File

@ -1,3 +1,5 @@
import role from './role'
export default {
title: '系统管理',
subTitle: '系统设置',
@ -115,12 +117,13 @@ export default {
permissionSetting: '资源权限配置',
setting: {
management: '管理',
managementDesc: '可对该资源进行删改操作',
check: '查看',
authorization: '授权',
},
priority: {
label: '资源权限优先级',
role: '按角色',
checkDesc: '仅能查看使用该资源',
role: '按用户角色',
roleDesc: '根据用户角色中的权限授权用户对该资源的操作权限',
notAuthorized: '不授权',
configure: '配置权限',
},
},
resource_management: {

View File

@ -109,18 +109,20 @@ export default {
enableSSL: '啟用 SSL如果 SMTP 端口是 465通常需要啟用 SSL',
enableTLS: '啟用 TLS如果 SMTP 端口是 587通常需要啟用 TLS',
},
resourceAuthorization: {
title: '資源授',
title: '資源授',
member: '成員',
permissionSetting: '資源限配置',
permissionSetting: '資源限配置',
setting: {
management: '管理',
managementDesc: '可對該資源進行刪改操作',
check: '查看',
authorization: '授权',
},
priority: {
label: '資源权限优先级',
role: '按角色',
checkDesc: '僅能查看使用該資源',
role: '按用戶角色',
roleDesc: '根據用戶角色中的權限授權用戶對該資源的操作權限',
notAuthorized: '不授權',
configure: '配置權限',
},
},
resource_management: {

View File

@ -359,12 +359,12 @@ const nextChatRecord = () => {
}
}
const pre_disable = computed(() => {
let index = tableIndexMap.value[currentChatId.value] - 1
const index = tableIndexMap.value[currentChatId.value] - 1
return index < 0 && paginationConfig.current_page <= 1
})
const next_disable = computed(() => {
let index = tableIndexMap.value[currentChatId.value] + 1
const index = tableIndexMap.value[currentChatId.value] + 1
return (
index >= tableData.value.length &&
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=

View File

@ -51,10 +51,11 @@
>{{ $t('views.document.generateQuestion.title') }}
</el-button>
<el-button
@click="openknowledgeDialog()"
@click="openBatchEditDocument"
:disabled="multipleSelection.length === 0"
v-if="permissionPrecise.doc_migrate(id)"
>{{ $t('views.document.setting.migration') }}
v-if="permissionPrecise.doc_edit(id)"
>
{{ $t('common.setting') }}
</el-button>
<el-dropdown v-if="MoreFilledPermission0(id)">
<el-button class="ml-12 mr-12">
@ -63,11 +64,11 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
@click="openBatchEditDocument"
@click="openknowledgeDialog()"
:disabled="multipleSelection.length === 0"
v-if="permissionPrecise.doc_edit(id)"
v-if="permissionPrecise.doc_migrate(id)"
>
{{ $t('common.setting') }}
{{ $t('views.document.setting.migration') }}
</el-dropdown-item>
<el-dropdown-item
divided
@ -434,16 +435,12 @@
"
@click="cancelTask(row, TaskType.GENERATE_PROBLEM)"
>
<AppIcon
iconName="app-generate-question"
class="color-secondary"
></AppIcon>
<el-icon class="color-secondary"><Close /></el-icon>
{{ $t('views.document.setting.cancelGenerateQuestion') }}
</el-dropdown-item>
<el-dropdown-item
v-else
@click="openGenerateDialog(row)"
v-if="permissionPrecise.doc_generate(id)"
v-else-if="permissionPrecise.doc_generate(id)"
>
<AppIcon
iconName="app-generate-question"
@ -494,18 +491,6 @@
</span>
</template>
<template v-if="knowledgeDetail?.type === 1 || knowledgeDetail?.type === 2">
<el-tooltip
effect="dark"
:content="$t('views.knowledge.setting.sync')"
placement="top"
v-if="permissionPrecise.sync(id)"
>
<span class="mr-4">
<el-button type="primary" text @click.stop="syncDocument(row)">
<AppIcon iconName="app-sync"></AppIcon>
</el-button>
</span>
</el-tooltip>
<el-tooltip
effect="dark"
:content="$t('views.document.setting.cancelVectorization')"
@ -538,6 +523,18 @@
</el-button>
</span>
</el-tooltip>
<el-tooltip
effect="dark"
:content="$t('common.setting')"
placement="top"
v-if="permissionPrecise.doc_edit(id)"
>
<span class="mr-4">
<el-button type="primary" text @click.stop="settingDoc(row)">
<AppIcon iconName="app-setting"></AppIcon>
</el-button>
</span>
</el-tooltip>
<span @click.stop>
<el-dropdown trigger="click" v-if="MoreFilledPermission2(id)">
<el-button text type="primary">
@ -546,11 +543,11 @@
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
@click="settingDoc(row)"
v-if="permissionPrecise.doc_edit(id)"
@click="syncDocument(row)"
v-if="permissionPrecise.sync(id)"
>
<AppIcon iconName="app-setting"></AppIcon>
{{ $t('common.setting') }}</el-dropdown-item
<AppIcon iconName="app-sync" class="color-secondary"></AppIcon>
{{ $t('views.knowledge.setting.sync') }}</el-dropdown-item
>
<el-dropdown-item
v-if="
@ -561,43 +558,45 @@
"
@click="cancelTask(row, TaskType.GENERATE_PROBLEM)"
>
<AppIcon iconName="app-generate-question"></AppIcon>
<el-icon class="color-secondary"><Close /></el-icon>
{{ $t('views.document.setting.cancelGenerateQuestion') }}
</el-dropdown-item>
<el-dropdown-item
v-else
@click="openGenerateDialog(row)"
v-if="permissionPrecise.doc_generate(id)"
v-else-if="permissionPrecise.doc_generate(id)"
>
<AppIcon iconName="app-generate-question"></AppIcon>
<AppIcon
iconName="app-generate-question"
class="color-secondary"
></AppIcon>
{{ $t('views.document.generateQuestion.title') }}
</el-dropdown-item>
<el-dropdown-item
@click="openknowledgeDialog(row)"
v-if="permissionPrecise.doc_migrate(id)"
>
<AppIcon iconName="app-migrate"></AppIcon>
<AppIcon iconName="app-migrate" class="color-secondary"></AppIcon>
{{ $t('views.document.setting.migration') }}
</el-dropdown-item>
<el-dropdown-item
@click="exportDocument(row)"
v-if="permissionPrecise.doc_export(id)"
>
<AppIcon iconName="app-export"></AppIcon>
<AppIcon iconName="app-export" class="color-secondary"></AppIcon>
{{ $t('views.document.setting.export') }} Excel
</el-dropdown-item>
<el-dropdown-item
@click="exportDocumentZip(row)"
v-if="permissionPrecise.doc_export(id)"
>
<AppIcon iconName="app-export"></AppIcon>
<AppIcon iconName="app-export" class="color-secondary"></AppIcon>
{{ $t('views.document.setting.export') }} Zip
</el-dropdown-item>
<el-dropdown-item
@click.stop="deleteDocument(row)"
v-if="permissionPrecise.doc_delete(id)"
>
<AppIcon iconName="app-delete"></AppIcon>
<AppIcon iconName="app-delete" class="color-secondary"></AppIcon>
{{ $t('common.delete') }}
</el-dropdown-item>
</el-dropdown-menu>
@ -712,7 +711,7 @@ const permissionPrecise = computed(() => {
const MoreFilledPermission0 = (id: string) => {
return (
permissionPrecise.value.doc_edit(id) ||
permissionPrecise.value.doc_migrate(id) ||
(knowledgeDetail?.value.type === 1 && permissionPrecise.value.doc_sync(id)) ||
(knowledgeDetail?.value.type === 2 && permissionPrecise.value.doc_sync(id)) ||
permissionPrecise.value.doc_delete(id)
@ -731,7 +730,7 @@ const MoreFilledPermission1 = (id: string) => {
const MoreFilledPermission2 = (id: string) => {
return (
permissionPrecise.value.doc_edit(id) ||
permissionPrecise.value.sync(id) ||
permissionPrecise.value.doc_generate(id) ||
permissionPrecise.value.doc_migrate(id) ||
permissionPrecise.value.doc_export(id) ||

View File

@ -47,11 +47,10 @@ import { groupBy } from 'lodash'
import type { knowledgeData } from '@/api/type/knowledge'
import { t } from '@/locales'
import { loadSharedApi } from '@/utils/dynamics-api/shared-api'
import modelResourceApi from '@/api/system-resource-management/model'
const props = defineProps<{
data?: {
type: Object
default: () => {}
type: object
default: () => null
}
apiType: 'systemShare' | 'workspace' | 'systemManage'
}>()

View File

@ -0,0 +1,308 @@
<template>
<div class="permission-setting p-24 flex">
<div class="resource-authorization__table">
<h4 class="mb-16">{{ $t('views.system.resourceAuthorization.permissionSetting') }}</h4>
<div class="flex-between mb-16">
<el-button
type="primary"
v-if="
hasPermission(permissionObj[(route.meta?.resource as string) || 'APPLICATION'], 'OR')
"
: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: 80px"
@change="search_type_change"
>
<el-option :label="$t('common.name')" value="name" />
<el-option
:label="$t('views.model.modelForm.permissionType.label')"
value="publish_status"
/>
</el-select>
<el-input
v-if="searchType === 'name'"
v-model="searchForm.name"
@change="searchHandle"
:placeholder="$t('common.searchBar.placeholder')"
style="width: 220px"
clearable
/>
<el-select
v-else-if="searchType === 'publish_status'"
v-model="searchForm.publish_status"
@change="searchHandle"
filterable
clearable
multiple
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="props.data"
:pagination-config="paginationConfig"
@sizeChange="handleSizeChange"
@changePage="props.getData"
@selection-change="handleSelectionChange"
:maxTableHeight="320"
:row-key="(row: any) => row.id"
>
<el-table-column type="selection" width="55" :reserve-selection="true" />
<el-table-column prop="name" :label="$t('common.name')">
<template #default="{ row }">
<el-space :size="8">
<!--  知识库 icon -->
<KnowledgeIcon :size="20" v-if="isKnowledge" :type="row.icon" />
<!--  应用/工具 自定义 icon -->
<el-avatar
v-else-if="isAppIcon(row?.icon) && !isModel"
style="background: none"
shape="square"
:size="20"
>
<img :src="resetUrl(row?.icon)" alt="" />
</el-avatar>
<!--  应用 icon -->
<LogoIcon v-else-if="isApplication" height="20px" />
<!-- 工具 icon -->
<el-avatar v-else-if="isTool" class="avatar-green" shape="square" :size="20">
<img src="@/assets/workflow/icon_tool.svg" style="width: 58%" alt="" />
</el-avatar>
<!-- 模型 icon -->
<span
v-else-if="isModel"
style="width: 20px; height: 20px; display: inline-block"
:innerHTML="getProviderIcon(row)"
></span>
<span :title="row?.name" class="ellipsis-1">
{{ row?.name }}
</span>
</el-space>
</template>
</el-table-column>
<el-table-column :label="$t('common.operation')" align="left">
<template #default="{ row }">
<el-radio-group
v-model="row.permission"
@change="(val: any) => submitPermissions(val, row)"
>
<template v-for="(item, index) in permissionOptions" :key="index">
<el-radio :value="item.value" class="mr-16">{{ item.label }}</el-radio>
</template>
</el-radio-group>
</template>
</el-table-column>
</app-table>
</div>
<!-- 批量配置 弹出层 -->
<el-dialog
v-model="dialogVisible"
:title="$t('views.system.resourceAuthorization.setting.configure')"
destroy-on-close
@close="closeDialog"
>
<el-radio-group v-model="radioPermission" class="radio-block">
<template v-for="(item, index) in permissionOptions" :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>
<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>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, computed, reactive } from 'vue'
import { useRoute } from 'vue-router'
import type { Provider } from '@/api/type/model'
import { AuthorizationEnum } from '@/enums/system'
import { isAppIcon, resetUrl } from '@/utils/common'
import { RoleConst, PermissionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
import { ComplexPermission } from '@/utils/permission/type'
import { permissionOptions } from '@/views/system/resource-authorization/constant'
import useStore from '@/stores'
const { model, user } = useStore()
const route = useRoute()
const props = defineProps<{
data: any[]
type: string
getData?: () => void
}>()
const emit = defineEmits(['submitPermissions'])
const permissionObj = ref<any>({
APPLICATION: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
KNOWLEDGE: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.KNOWLEDGE_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.KNOWLEDGE_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
TOOL: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.TOOL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.TOOL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
MODEL: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.MODEL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.MODEL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
})
const isKnowledge = computed(() => props.type === AuthorizationEnum.KNOWLEDGE)
const isApplication = computed(() => props.type === AuthorizationEnum.APPLICATION)
const isTool = computed(() => props.type === AuthorizationEnum.TOOL)
const isModel = computed(() => props.type === AuthorizationEnum.MODEL)
const multipleTableRef = ref()
const searchType = ref('name')
const searchForm = ref<any>({
name: '',
publish_status: undefined,
})
const search_type_change = () => {
searchForm.value = { name: '', create_user: '' }
}
const paginationConfig = reactive({
current_page: 1,
page_size: 20,
total: 0,
})
function handleSizeChange() {
paginationConfig.current_page = 1
if (props.getData) {
props.getData()
}
}
function searchHandle() {
paginationConfig.current_page = 1
if (props.getData) {
props.getData()
}
}
const multipleSelection = ref<any[]>([])
const handleSelectionChange = (val: any[]) => {
multipleSelection.value = val
}
const dialogVisible = ref(false)
const radioPermission = ref('')
function openMulConfigureDialog() {
if (multipleSelection.value.length === 0) {
return
}
dialogVisible.value = true
}
function submitDialog() {
if (multipleSelection.value.length === 0 || !radioPermission.value) {
return
}
const obj = multipleSelection.value.map((item) => ({
target_id: item.id,
permission: radioPermission.value,
}))
emit('submitPermissions', obj)
closeDialog()
}
function closeDialog() {
dialogVisible.value = false
radioPermission.value = ''
multipleSelection.value = []
multipleTableRef.value?.clearSelection()
}
function submitPermissions(value: string, row: any) {
const obj = [
{
target_id: row.id,
permission: value,
},
]
emit('submitPermissions', obj)
}
const provider_list = ref<Array<Provider>>([])
function getProvider() {
model.asyncGetProvider().then((res: any) => {
provider_list.value = res?.data
})
}
const getProviderIcon = computed(() => {
return (row: any) => {
return provider_list.value.find((p) => p.provider === row.icon)?.icon
}
})
onMounted(() => {
if (isModel.value) {
getProvider()
}
})
defineExpose({
paginationConfig,
searchForm,
searchType,
})
</script>
<style lang="scss" scoped>
.permission-setting {
flex: 1;
overflow: hidden;
box-sizing: border-box;
width: 100%;
flex-direction: column;
}
</style>

View File

@ -0,0 +1,25 @@
import { AuthorizationEnum } from '@/enums/system'
import { t } from '@/locales'
export const permissionOptions = [
{
label: t('views.system.resourceAuthorization.setting.notAuthorized'),
value: AuthorizationEnum.NOT_AUTH,
desc: '',
},
{
label: t('views.system.resourceAuthorization.setting.check'),
value: AuthorizationEnum.VIEW,
desc: t('views.system.resourceAuthorization.setting.checkDesc'),
},
{
label: t('views.system.resourceAuthorization.setting.management'),
value: AuthorizationEnum.MANAGE,
desc: t('views.system.resourceAuthorization.setting.managementDesc'),
},
{
label: t('views.system.resourceAuthorization.setting.role'),
value: AuthorizationEnum.ROLE,
desc: t('views.system.resourceAuthorization.setting.roleDesc'),
},
]

View File

@ -21,8 +21,8 @@
/>
</div>
<el-card style="--el-card-padding: 0">
<div class="flex main-calc-height">
<el-card style="--el-card-padding: 0; height: calc(100vh - 140px)">
<div class="flex">
<div class="resource-authorization__left border-r">
<div class="p-24 pb-0">
<h4 class="mb-12">{{ $t('views.system.resourceAuthorization.member') }}</h4>
@ -45,11 +45,15 @@
<template #default="{ row }">
<div class="flex-between">
<div class="flex">
<span class="mr-8">{{ row.nick_name }}</span>
<TagGroup
:tags="row.roles"
<span class="mr-8 ellipsis-1" :title="row.nick_name">{{
row.nick_name
}}</span>
<el-text
class="color-input-placeholder ellipsis-1"
:title="row.roles.join('')"
v-if="hasPermission([EditionConst.IS_EE, EditionConst.IS_PE], 'OR')"
/>
>({{ row.roles?.join('') }})</el-text
>
</div>
</div>
</template>
@ -58,46 +62,13 @@
</el-scrollbar>
</div>
</div>
<div class="permission-setting p-24 flex" v-loading="rLoading">
<div class="resource-authorization__table">
<h4 class="mb-16">{{ $t('views.system.resourceAuthorization.permissionSetting') }}</h4>
<!-- <el-tabs
v-model="activeName"
@tab-change="handleTabChange"
class="resource-authorization__tabs"
>
<el-tab-pane
v-for="(item, index) in settingTags"
:key="item.value"
:label="item.label"
:name="item.value"
> -->
<PermissionSetting
:data="activeData.data"
:type="activeData.type"
:tableHeight="tableHeight"
:manage="isManage(currentType)"
@refreshData="refreshData"
v-model:isRole="activeData.isRole"
></PermissionSetting>
<!-- </el-tab-pane> -->
<!-- </el-tabs> -->
</div>
<div class="submit-button">
<el-button
type="primary"
@click="submitPermissions"
v-if="
hasPermission(
permissionObj[(route.meta?.resource as string) || 'APPLICATION'],
'OR',
)
"
>{{ $t('common.save') }}</el-button
>
</div>
</div>
<PermissionTable
:data="permissionData"
:type="activeData.type"
ref="PermissionTableRef"
:getData="getPermissionList"
@submitPermissions="submitPermissions"
/>
</div>
</el-card>
</div>
@ -107,18 +78,17 @@
import { onMounted, ref, reactive, watch, computed } from 'vue'
import { useRoute } from 'vue-router'
import AuthorizationApi from '@/api/system/resource-authorization'
import PermissionSetting from './component/PermissionSetting.vue'
import PermissionTable from '@/views/system/resource-authorization/component/PermissionTable.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { AuthorizationEnum } from '@/enums/system'
import { t } from '@/locales'
import useStore from '@/stores'
import { cloneDeep } from 'lodash'
import { EditionConst, RoleConst, PermissionConst } from '@/utils/permission/data'
import { EditionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
import type { WorkspaceItem } from '@/api/type/workspace'
import { ComplexPermission } from '@/utils/permission/type'
import { loadPermissionApi } from '@/utils/dynamics-api/permission-api.ts'
import useStore from '@/stores'
const route = useRoute()
const { user } = useStore()
const loading = ref(false)
@ -128,79 +98,27 @@ const filterMember = ref<any[]>([]) // 搜索过滤后列表
const currentUser = ref<string>('')
const currentType = ref<string>('')
const filterText = ref('')
const tableHeight = ref(0)
const permissionData = ref<any[]>([])
const permissionObj = ref<any>({
APPLICATION: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.APPLICATION_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
KNOWLEDGE: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.KNOWLEDGE_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.KNOWLEDGE_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
TOOL: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.TOOL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.TOOL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
MODEL: new ComplexPermission(
[RoleConst.ADMIN, RoleConst.WORKSPACE_MANAGE],
[
PermissionConst.MODEL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT,
PermissionConst.MODEL_WORKSPACE_USER_RESOURCE_PERMISSION_EDIT
.getWorkspacePermissionWorkspaceManageRole,
],
[],
'OR',
),
})
const settingTags = reactive([
{
label: t('views.knowledge.title'),
type: AuthorizationEnum.KNOWLEDGE,
data: [] as any,
isRole: false,
},
{
label: t('views.application.title'),
type: AuthorizationEnum.APPLICATION,
data: [] as any,
isRole: false,
},
{
label: t('views.tool.title'),
type: AuthorizationEnum.TOOL,
data: [] as any,
isRole: false,
},
{
label: t('views.model.title'),
type: AuthorizationEnum.MODEL,
data: [] as any,
isRole: false,
},
])
// ///
const activeData = computed(() => {
const lastIndex = route.path.lastIndexOf('/')
const currentPathType = route.path.substring(lastIndex + 1).toUpperCase()
@ -219,51 +137,46 @@ watch(filterText, (val: any) => {
}
})
function isManage(type: string) {
return type === 'manage'
}
const flotTree = (tree: Array<any>, result: Array<any>) => {
tree.forEach((tItem) => {
result.push(tItem)
if (tItem.children) {
flotTree(tItem.children, result)
}
})
return result
}
function submitPermissions() {
const user_resource_permission_list = settingTags
.map((item: any, index: number) => {
return flotTree(item.data, [])
.filter((v: any) => !v.isFolder)
.map((v: any) => {
return {
target_id: v.id,
auth_target_type: item.value,
permission: v.permission,
auth_type: item.isRole ? 'ROLE' : 'RESOURCE_PERMISSION_GROUP',
}
})
})
.reduce((pre: any, next: any) => [...pre, ...next], [])
function submitPermissions(obj: any) {
const workspaceId = currentWorkspaceId.value || user.getWorkspaceId() || 'default'
AuthorizationApi.putResourceAuthorization(
workspaceId,
currentUser.value,
(route.meta?.resource as string) || 'APPLICATION',
{ user_resource_permission_list: user_resource_permission_list },
obj,
rLoading,
).then(() => {
MsgSuccess(t('common.submitSuccess'))
getWholeTree(currentUser.value)
getPermissionList()
})
}
const PermissionTableRef = ref()
const getPermissionList = () => {
const workspaceId = currentWorkspaceId.value || user.getWorkspaceId() || 'default'
const params: any = {}
if (PermissionTableRef.value.searchForm[PermissionTableRef.value.searchType]) {
params[PermissionTableRef.value.searchType] =
PermissionTableRef.value.searchForm[PermissionTableRef.value.searchType]
}
AuthorizationApi.getResourceAuthorization(
workspaceId,
currentUser.value,
(route.meta?.resource as string) || 'APPLICATION',
PermissionTableRef.value.paginationConfig,
params,
rLoading,
).then((res) => {
permissionData.value = res.data.records || []
PermissionTableRef.value.paginationConfig.total = res.data.total || 0
})
}
function clickMemberHandle(item: any) {
currentUser.value = item.id
currentType.value = item.type
getWholeTree(item.id)
getPermissionList()
}
function getMember(id?: string) {
@ -275,175 +188,13 @@ function getMember(id?: string) {
const member = (id && memberList.value.find((p: any) => p.user_id === id)) || null
currentUser.value = member ? member.id : memberList.value?.[0]?.id
currentType.value = member ? member.type : memberList.value?.[0]?.type
getWholeTree(currentUser.value)
getPermissionList()
} else {
activeData.value.data = []
permissionData.value = []
}
})
}
const dfsPermissionIndeterminateTrue = (arr: any = [], type: string) => {
return arr.every((item: any) => {
if (item.children?.length) {
item.permission[type] = dfsPermissionIndeterminateTrue(item.children, type)
}
return item.permission[type]
})
}
const dfsPermissionIndeterminate = (
arr: any = [],
type: string,
permissionHalf: any,
permissionHalfMap: any,
id: string,
) => {
arr.forEach((item: any) => {
if (item.isFolder) {
if (!permissionHalfMap[item.id]) {
permissionHalfMap[item.id] = cloneDeep(permissionHalf)
}
}
if (item.children?.length) {
dfsPermissionIndeterminate(item.children, type, permissionHalf, permissionHalfMap, item.id)
}
if (!item.isFolder) {
permissionHalfMap[id][type] = [...permissionHalfMap[id][type], item.permission[type]]
}
if (item.isFolder) {
//
const hasPermissions = permissionHalfMap[item.id][type]
const allTrue = hasPermissions.length && hasPermissions.every((p: boolean) => p)
const allFalse = hasPermissions.length && hasPermissions.every((p: boolean) => !p)
//
item.permissionHalf[type] = hasPermissions.length && !allTrue && !allFalse
//
if (item.children.some((ele: any) => ele.isFolder && ele.permissionHalf[type])) {
item.permissionHalf[type] = true
}
//
if (allTrue) {
item.permission[type] = true
item.permissionHalf[type] = false
}
//
if (
item.children.some((ele: any) => ele.permission[type]) &&
item.children.some((ele: any) => !ele.permission[type])
) {
item.permissionHalf[type] = true
}
}
})
}
const dfsFolder = (arr: any[] = [], folderIdMap: any) => {
arr.forEach((ele) => {
if (ele.permission) return
if (ele.children?.length) {
if (folderIdMap[ele.id]) {
ele.children = [...ele.children, ...folderIdMap[ele.id]]
}
dfsFolder(ele.children, folderIdMap)
} else {
ele.children = folderIdMap[ele.id] || []
}
ele.isFolder = true
ele.permission = {
VIEW: false,
MANAGE: false,
ROLE: false,
}
ele.permissionHalf = {
VIEW: false,
MANAGE: false,
ROLE: false,
}
})
}
function getFolder() {
const workspaceId = currentWorkspaceId.value || user.getWorkspaceId() || 'default'
return AuthorizationApi.getSystemFolder(workspaceId, activeData.value.type, {}, loading)
}
function getResourcePermissions(user_id: string) {
const workspaceId = currentWorkspaceId.value || user.getWorkspaceId() || 'default'
return AuthorizationApi.getResourceAuthorization(
workspaceId,
user_id,
(route.meta?.resource as string) || 'APPLICATION',
rLoading,
)
}
const getWholeTree = async (user_id: string) => {
const [parentRes, childrenRes] = await Promise.all([getFolder(), getResourcePermissions(user_id)])
// if (!childrenRes.data || Object.keys(childrenRes.data).length > 0) {
// settingTags.map((item: any) => {
let folderIdMap = []
const folderTree = cloneDeep((parentRes as unknown as any).data)
if (Object.keys(childrenRes.data).indexOf(activeData.value.type) !== -1) {
activeData.value.isRole =
childrenRes.data[activeData.value.type].length > 0 &&
hasPermission([EditionConst.IS_EE, EditionConst.IS_PE], 'OR')
? childrenRes.data[activeData.value.type][0].auth_type == 'ROLE'
: false
folderIdMap = getFolderIdMap(childrenRes.data[activeData.value.type])
dfsFolder(folderTree, folderIdMap)
const permissionHalf = {
VIEW: [],
MANAGE: [],
ROLE: [],
}
Object.keys(permissionHalf).forEach((ele) => {
dfsPermissionIndeterminateTrue(folderTree, ele)
dfsPermissionIndeterminate(folderTree, ele, cloneDeep(permissionHalf), {}, 'default')
})
if (activeData.value.type === AuthorizationEnum.MODEL) {
activeData.value.data = folderTree[0].children
} else {
activeData.value.data = folderTree
}
} else {
activeData.value.data = []
}
// })
// }
}
const refreshData = () => {
settingTags.map((item: any) => {
if (activeData.value.type === item.type) {
const permissionHalf = {
VIEW: [],
MANAGE: [],
ROLE: [],
}
Object.keys(permissionHalf).forEach((ele) => {
dfsPermissionIndeterminateTrue(item.data, ele)
dfsPermissionIndeterminate(item.data, ele, cloneDeep(permissionHalf), {}, 'default')
})
}
})
}
const getFolderIdMap = (arr: any = []) => {
return arr.reduce((pre: any, next: any) => {
if (pre[next.folder_id]) {
pre[next.folder_id].push(next)
} else {
pre[next.folder_id] = [next]
}
return pre
}, {})
}
const workspaceList = ref<WorkspaceItem[]>([])
const currentWorkspaceId = ref<string | undefined>('')
const currentWorkspace = computed(() => {
@ -461,12 +212,6 @@ function changeWorkspace(item: WorkspaceItem) {
}
onMounted(() => {
tableHeight.value = window.innerHeight - 300
window.onresize = () => {
return (() => {
tableHeight.value = window.innerHeight - 300
})()
}
if (user.isEE()) {
getWorkspaceList()
}
@ -481,20 +226,6 @@ onMounted(() => {
width: var(--setting-left-width);
min-width: var(--setting-left-width);
}
.permission-setting {
flex: 1;
overflow: hidden;
box-sizing: border-box;
width: 100%;
flex-direction: column;
position: relative;
.submit-button {
position: absolute;
top: 24px;
right: 24px;
}
}
.list-height-left {
height: calc(100vh - 240px);
}