feat: Workplace resource authorization (#3864)

Co-authored-by: wangdan-fit2cloud <dan.wang@fit2cloud.com>
This commit is contained in:
shaohuzhang1 2025-08-15 17:48:52 +08:00 committed by GitHub
parent a700bc126f
commit 33806f66d0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 441 additions and 31 deletions

View File

@ -5,7 +5,53 @@ import type { pageRequest } from '@/api/type/common'
const prefix = '/workspace'
/**
*
*
* @query
*/
const getWorkspaceResourceAuthorization: (
workspace_id: string,
target: string,
resource: string,
page: pageRequest,
params?: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (workspace_id, target, resource, page, params, loading) => {
return get(
`${prefix}/${workspace_id}/resource_user_permission/resource/${target}/resource/${resource}/${page.current_page}/${page.page_size}`,
params,
loading,
)
}
/**
*
* @param member_id
* @param {
[
{
"user_id": "string",
"permission": "NOT_AUTH"
}
]
}
*/
const putWorkspaceResourceAuthorization: (
workspace_id: string,
target: string,
resource: string,
body: any,
loading?: Ref<boolean>,
) => Promise<Result<any>> = (workspace_id, target, resource, body, loading) => {
return put(
`${prefix}/${workspace_id}/resource_user_permission/resource/${target}/resource/${resource}`,
body,
{},
loading,
)
}
/**
*
* @query
*/
const getResourceAuthorization: (
@ -24,7 +70,7 @@ const getResourceAuthorization: (
}
/**
*
*
* @param member_id
* @param {
[
@ -102,4 +148,6 @@ export default {
getUserList,
getUserMember,
getSystemFolder,
getWorkspaceResourceAuthorization,
putWorkspaceResourceAuthorization
}

View File

@ -0,0 +1,291 @@
<template>
<el-drawer
v-model="drawerVisible"
:title="$t('views.system.resourceAuthorization.title')"
size="60%"
:append-to-body="true"
:modal="false"
>
<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="publish_status"
/>
</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 === '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="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 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>
<!-- 批量配置 弹出层 -->
<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>
</el-drawer>
</template>
<script setup lang="ts">
import { ref, onMounted, watch, computed, reactive } from 'vue'
import { permissionOptions } from '@/views/system/resource-authorization/constant'
import AuthorizationApi from '@/api/system/resource-authorization'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { t } from '@/locales'
import useStore from '@/stores'
const { user } = useStore()
const props = defineProps<{
type: string
}>()
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 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 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) => ({
user_id: item.id,
permission: radioPermission.value,
}))
submitPermissions(obj)
closeDialog()
}
function closeDialog() {
dialogVisible.value = false
radioPermission.value = ''
multipleSelection.value = []
multipleTableRef.value?.clearSelection()
}
function permissionsHandle(val: any, row: any) {
const obj = [
{
user_id: row.id,
permission: val,
},
]
submitPermissions(obj)
}
function submitPermissions(obj: any) {
const workspaceId = user.getWorkspaceId() || 'default'
AuthorizationApi.putWorkspaceResourceAuthorization(
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]
}
AuthorizationApi.getWorkspaceResourceAuthorization(
workspaceId,
targetId.value,
props.type,
paginationConfig,
params,
loading,
).then((res) => {
permissionData.value = res.data.records || []
paginationConfig.total = res.data.total || 0
})
}
const open = (id: string) => {
targetId.value = id
drawerVisible.value = true
getPermissionList()
}
defineExpose({
open,
})
</script>
<style lang="scss" scoped></style>

View File

@ -19,4 +19,5 @@ export enum SourceTypeEnum {
KNOWLEDGE = 'KNOWLEDGE',
APPLICATION = 'APPLICATION',
TOOL = 'TOOL',
MODEL = 'MODEL',
}

View File

@ -3,10 +3,6 @@ export enum AuthorizationEnum {
VIEW = 'VIEW',
ROLE = 'ROLE',
NOT_AUTH = 'NOT_AUTH',
KNOWLEDGE = 'KNOWLEDGE',
APPLICATION = 'APPLICATION',
MODEL = 'MODEL',
TOOL = 'TOOL',
}
export enum RoleTypeEnum {

View File

@ -249,6 +249,14 @@
<AppIcon iconName="app-setting" class="color-secondary"></AppIcon>
{{ $t('common.setting') }}
</el-dropdown-item>
<el-dropdown-item @click.stop="openAuthorization(item)">
<AppIcon
iconName="app-resource-authorization"
class="color-secondary"
></AppIcon>
{{ $t('views.system.resourceAuthorization.title') }}
</el-dropdown-item>
<el-dropdown-item
@click.stop="openMoveToDialog(item)"
v-if="permissionPrecise.edit(item.id) && apiType === 'workspace'"
@ -301,6 +309,10 @@
@refresh="refreshApplicationList"
v-if="apiType === 'workspace'"
/>
<ResourceAuthorizationDrawer
:type="SourceTypeEnum.APPLICATION"
ref="ResourceAuthorizationDrawerRef"
/>
</LayoutContainer>
</template>
@ -310,6 +322,7 @@ import CreateApplicationDialog from '@/views/application/component/CreateApplica
import CreateFolderDialog from '@/components/folder-tree/CreateFolderDialog.vue'
import CopyApplicationDialog from '@/views/application/component/CopyApplicationDialog.vue'
import MoveToDialog from '@/components/folder-tree/MoveToDialog.vue'
import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
import ApplicationApi from '@/api/application/application'
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
import useStore from '@/stores'
@ -318,7 +331,7 @@ import { useRouter, useRoute } from 'vue-router'
import { isWorkFlow } from '@/utils/application'
import { resetUrl } from '@/utils/common'
import { dateFormat } from '@/utils/time'
import { SourceTypeEnum, ValidType, ValidCount } from '@/enums/common'
import { SourceTypeEnum } from '@/enums/common'
import permissionMap from '@/permission'
import WorkspaceApi from '@/api/workspace/workspace'
import { hasPermission } from '@/utils/permission'
@ -358,6 +371,11 @@ const folderList = ref<any[]>([])
const applicationList = ref<any[]>([])
const CopyApplicationDialogRef = ref()
const ResourceAuthorizationDrawerRef = ref()
function openAuthorization(item: any) {
ResourceAuthorizationDrawerRef.value.open(item.id)
}
const MoveToDialogRef = ref()
function openMoveToDialog(data: any) {

View File

@ -258,7 +258,16 @@
<AppIcon iconName="app-lock" class="color-secondary"></AppIcon>
{{ $t('views.shared.authorized_workspace') }}</el-dropdown-item
>
<el-dropdown-item
@click.stop="openAuthorization(item)"
v-if="apiType === 'workspace'"
>
<AppIcon
iconName="app-resource-authorization"
class="color-secondary"
></AppIcon>
{{ $t('views.system.resourceAuthorization.title') }}
</el-dropdown-item>
<el-dropdown-item
@click.stop="openMoveToDialog(item)"
v-if="permissionPrecise.edit(item.id) && apiType === 'workspace'"
@ -328,6 +337,11 @@
@refresh="refreshKnowledgeList"
v-if="apiType === 'workspace'"
/>
<ResourceAuthorizationDrawer
:type="SourceTypeEnum.KNOWLEDGE"
ref="ResourceAuthorizationDrawerRef"
v-if="apiType === 'workspace'"
/>
</template>
<script lang="ts" setup>
@ -342,6 +356,7 @@ import CreateFolderDialog from '@/components/folder-tree/CreateFolderDialog.vue'
import MoveToDialog from '@/components/folder-tree/MoveToDialog.vue'
import GenerateRelatedDialog from '@/components/generate-related-dialog/index.vue'
import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog.vue'
import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import useStore from '@/stores'
import { numberFormat } from '@/utils/common'
@ -407,6 +422,11 @@ const paginationConfig = reactive({
total: 0,
})
const ResourceAuthorizationDrawerRef = ref()
function openAuthorization(item: any) {
ResourceAuthorizationDrawerRef.value.open(item.id)
}
const MoveToDialogRef = ref()
function openMoveToDialog(data: any) {
// 2

View File

@ -100,6 +100,10 @@
<AppIcon iconName="app-setting" class="color-secondary"></AppIcon>
{{ $t('views.model.modelForm.title.paramSetting') }}
</el-dropdown-item>
<el-dropdown-item @click.stop="openAuthorization(model)" v-if="apiType === 'workspace'">
<AppIcon iconName="app-resource-authorization" class="color-secondary"></AppIcon>
{{ $t('views.system.resourceAuthorization.title') }}
</el-dropdown-item>
<el-dropdown-item
divided
text
@ -119,6 +123,11 @@
ref="AuthorizedWorkspaceDialogRef"
v-if="isSystemShare"
></AuthorizedWorkspace>
<ResourceAuthorizationDrawer
:type="SourceTypeEnum.MODEL"
ref="ResourceAuthorizationDrawerRef"
v-if="apiType === 'workspace'"
/>
</card-box>
</template>
<script setup lang="ts">
@ -130,6 +139,8 @@ import { MsgConfirm, MsgSuccess } from '@/utils/message'
import { modelType } from '@/enums/model'
import ParamSettingDialog from './ParamSettingDialog.vue'
import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog.vue'
import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
import { SourceTypeEnum } from '@/enums/common'
import { t } from '@/locales'
import permissionMap from '@/permission'
import { useRoute } from 'vue-router'
@ -146,10 +157,8 @@ const props = defineProps<{
apiType: 'systemShare' | 'workspace' | 'systemManage'
}>()
const apiType = props.apiType
const isSystemShare = computed(() => {
return apiType === 'systemShare'
return props.apiType === 'systemShare'
})
const permissionPrecise = computed(() => {
@ -162,6 +171,11 @@ const MoreFilledPermission = (id: any) => {
)
}
const ResourceAuthorizationDrawerRef = ref()
function openAuthorization(item: any) {
ResourceAuthorizationDrawerRef.value.open(item.id)
}
const downModel = ref<Model>()
const currentModel = computed(() => {

View File

@ -178,6 +178,7 @@
import { ref, onMounted, watch, computed } from 'vue'
import type { Provider } from '@/api/type/model'
import { AuthorizationEnum } from '@/enums/system'
import { SourceTypeEnum } from '@/enums/common'
import { isAppIcon, resetUrl } from '@/utils/common'
import { EditionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
@ -202,10 +203,10 @@ const radioRole = computed({
emit('update:isRole', v)
},
})
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 isKnowledge = computed(() => props.type === SourceTypeEnum.KNOWLEDGE)
const isApplication = computed(() => props.type === SourceTypeEnum.APPLICATION)
const isTool = computed(() => props.type === SourceTypeEnum.TOOL)
const isModel = computed(() => props.type === SourceTypeEnum.MODEL)
const defaultExpandKeys = computed(() => (props.data?.length > 0 ? [props.data[0]?.id] : []))
const dfsPermission = (arr: any = [], Name: string | number, e: boolean, idArr: any[]) => {
arr.map((item: any) => {

View File

@ -23,7 +23,7 @@
<el-option :label="$t('common.name')" value="name" />
<el-option
:label="$t('views.model.modelForm.permissionType.label')"
value="publish_status"
value="permission"
/>
</el-select>
<el-input
@ -35,8 +35,8 @@
clearable
/>
<el-select
v-else-if="searchType === 'publish_status'"
v-model="searchForm.publish_status"
v-else-if="searchType === 'permission'"
v-model="searchForm.permission"
@change="searchHandle"
filterable
clearable
@ -139,7 +139,7 @@
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 { SourceTypeEnum } from '@/enums/common'
import { isAppIcon, resetUrl } from '@/utils/common'
import { RoleConst, PermissionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
@ -196,20 +196,20 @@ const permissionObj = ref<any>({
'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 isKnowledge = computed(() => props.type === SourceTypeEnum.KNOWLEDGE)
const isApplication = computed(() => props.type === SourceTypeEnum.APPLICATION)
const isTool = computed(() => props.type === SourceTypeEnum.TOOL)
const isModel = computed(() => props.type === SourceTypeEnum.MODEL)
const multipleTableRef = ref()
const searchType = ref('name')
const searchForm = ref<any>({
name: '',
publish_status: undefined,
permission: undefined,
})
const search_type_change = () => {
searchForm.value = { name: '', create_user: '' }
searchForm.value = { name: '', permission: undefined }
}
const paginationConfig = reactive({

View File

@ -77,11 +77,11 @@
<script lang="ts" setup>
import { onMounted, ref, reactive, watch, computed } from 'vue'
import { useRoute } from 'vue-router'
import AuthorizationApi from '@/api/system/resource-authorization'
import PermissionTable from '@/views/system/resource-authorization/component/PermissionTable.vue'
import { MsgSuccess, MsgConfirm } from '@/utils/message'
import { AuthorizationEnum } from '@/enums/system'
import { SourceTypeEnum } from '@/enums/common'
import { t } from '@/locales'
import AuthorizationApi from '@/api/system/resource-authorization'
import { EditionConst } from '@/utils/permission/data'
import { hasPermission } from '@/utils/permission/index'
import type { WorkspaceItem } from '@/api/type/workspace'
@ -103,19 +103,19 @@ const permissionData = ref<any[]>([])
const settingTags = reactive([
{
label: t('views.knowledge.title'),
type: AuthorizationEnum.KNOWLEDGE,
type: SourceTypeEnum.KNOWLEDGE,
},
{
label: t('views.application.title'),
type: AuthorizationEnum.APPLICATION,
type: SourceTypeEnum.APPLICATION,
},
{
label: t('views.tool.title'),
type: AuthorizationEnum.TOOL,
type: SourceTypeEnum.TOOL,
},
{
label: t('views.model.title'),
type: AuthorizationEnum.MODEL,
type: SourceTypeEnum.MODEL,
},
])
// ///

View File

@ -250,6 +250,16 @@
<AppIcon iconName="app-operation" class="color-secondary"></AppIcon>
{{ $t('common.param.initParam') }}
</el-dropdown-item>
<el-dropdown-item
@click.stop="openAuthorization(item)"
v-if="apiType === 'workspace'"
>
<AppIcon
iconName="app-resource-authorization"
class="color-secondary"
></AppIcon>
{{ $t('views.system.resourceAuthorization.title') }}
</el-dropdown-item>
<el-dropdown-item
@click.stop="openMoveToDialog(item)"
v-if="permissionPrecise.copy(item.id) && apiType === 'workspace'"
@ -308,6 +318,11 @@
@refresh="refreshToolList"
v-if="apiType === 'workspace'"
/>
<ResourceAuthorizationDrawer
:type="SourceTypeEnum.TOOL"
ref="ResourceAuthorizationDrawerRef"
v-if="apiType === 'workspace'"
/>
</template>
<script lang="ts" setup>
@ -322,6 +337,7 @@ import AuthorizedWorkspace from '@/views/system-shared/AuthorizedWorkspaceDialog
import ToolStoreDialog from '@/views/tool/toolStore/ToolStoreDialog.vue'
import AddInternalToolDialog from '@/views/tool/toolStore/AddInternalToolDialog.vue'
import MoveToDialog from '@/components/folder-tree/MoveToDialog.vue'
import ResourceAuthorizationDrawer from '@/components/resource-authorization-drawer/index.vue'
import { resetUrl } from '@/utils/common'
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
import { SourceTypeEnum } from '@/enums/common'
@ -366,6 +382,11 @@ const MoreFieldPermission = (id: any) => {
)
}
const ResourceAuthorizationDrawerRef = ref()
function openAuthorization(item: any) {
ResourceAuthorizationDrawerRef.value.open(item.id)
}
const InitParamDrawerRef = ref()
const search_type = ref('name')
const search_form = ref<any>({