2025-06-13 03:02:03 +00:00
|
|
|
<template>
|
2025-06-26 08:36:08 +00:00
|
|
|
<div class="workspace-manage p-16-24">
|
2025-06-13 03:02:03 +00:00
|
|
|
<h2 class="mb-16">{{ $t('views.workspace.title') }}</h2>
|
2025-06-26 08:36:08 +00:00
|
|
|
<el-card style="--el-card-padding: 0">
|
2025-06-13 03:02:03 +00:00
|
|
|
<div class="flex h-full">
|
2025-06-26 08:36:08 +00:00
|
|
|
<div class="workspace-left border-r">
|
|
|
|
|
<div class="p-24 pb-0">
|
|
|
|
|
<div class="flex-between mb-12">
|
|
|
|
|
<h4 class="medium">{{ $t('views.workspace.list') }}</h4>
|
|
|
|
|
<el-tooltip
|
|
|
|
|
effect="dark"
|
|
|
|
|
:content="`${$t('common.create')}${$t('views.workspace.title')}`"
|
|
|
|
|
placement="top"
|
2025-06-19 12:07:40 +00:00
|
|
|
>
|
2025-06-26 08:36:08 +00:00
|
|
|
<el-button
|
|
|
|
|
type="primary"
|
|
|
|
|
text
|
|
|
|
|
@click="createOrUpdateWorkspace()"
|
|
|
|
|
v-hasPermission="[RoleConst.ADMIN, PermissionConst.WORKSPACE_CREATE]"
|
|
|
|
|
>
|
|
|
|
|
<el-icon :size="18"><Plus /></el-icon>
|
|
|
|
|
</el-button>
|
|
|
|
|
</el-tooltip>
|
|
|
|
|
</div>
|
|
|
|
|
<el-input
|
|
|
|
|
v-model="filterText"
|
|
|
|
|
:placeholder="$t('common.search')"
|
|
|
|
|
prefix-icon="Search"
|
|
|
|
|
clearable
|
|
|
|
|
/>
|
2025-06-13 03:02:03 +00:00
|
|
|
</div>
|
|
|
|
|
<div class="list-height-left">
|
|
|
|
|
<el-scrollbar v-loading="loading">
|
2025-06-26 08:36:08 +00:00
|
|
|
<div class="p-16">
|
|
|
|
|
<common-list
|
|
|
|
|
:data="filterList"
|
|
|
|
|
@click="clickWorkspace"
|
|
|
|
|
:default-active="currentWorkspace?.id"
|
|
|
|
|
@mouseenter="mouseenter"
|
|
|
|
|
@mouseleave="mouseId = ''"
|
|
|
|
|
>
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<div class="flex-between">
|
|
|
|
|
<span class="ellipsis">{{ row.name }}</span>
|
|
|
|
|
<div @click.stop v-show="mouseId === row.id">
|
|
|
|
|
<el-dropdown :teleported="false">
|
|
|
|
|
<el-button text>
|
|
|
|
|
<el-icon class="color-secondary">
|
|
|
|
|
<MoreFilled />
|
|
|
|
|
</el-icon>
|
|
|
|
|
</el-button>
|
|
|
|
|
<template #dropdown>
|
|
|
|
|
<el-dropdown-menu style="min-width: 80px">
|
|
|
|
|
<el-dropdown-item
|
|
|
|
|
@click.stop="createOrUpdateWorkspace(row)"
|
|
|
|
|
class="p-8"
|
|
|
|
|
v-if="
|
|
|
|
|
hasPermission(
|
|
|
|
|
[RoleConst.ADMIN, PermissionConst.WORKSPACE_EDIT],
|
|
|
|
|
'OR',
|
|
|
|
|
)
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<el-icon><EditPen /></el-icon>
|
|
|
|
|
{{ $t('common.rename') }}
|
|
|
|
|
</el-dropdown-item>
|
|
|
|
|
<el-dropdown-item
|
|
|
|
|
@click.stop="deleteWorkspace(row)"
|
|
|
|
|
class="border-t p-8"
|
|
|
|
|
v-if="
|
|
|
|
|
row.id !== 'default' &&
|
|
|
|
|
hasPermission(
|
|
|
|
|
[RoleConst.ADMIN, PermissionConst.WORKSPACE_DELETE],
|
|
|
|
|
'OR',
|
|
|
|
|
)
|
|
|
|
|
"
|
|
|
|
|
>
|
|
|
|
|
<el-icon><Delete /></el-icon>
|
|
|
|
|
{{ $t('common.delete') }}
|
|
|
|
|
</el-dropdown-item>
|
|
|
|
|
</el-dropdown-menu>
|
|
|
|
|
</template>
|
|
|
|
|
</el-dropdown>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
<template #empty>
|
|
|
|
|
<span></span>
|
|
|
|
|
</template>
|
|
|
|
|
</common-list>
|
|
|
|
|
</div>
|
2025-06-13 03:02:03 +00:00
|
|
|
</el-scrollbar>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 右边 -->
|
2025-06-26 08:36:08 +00:00
|
|
|
<div class="workspace-right p-24" v-loading="loading">
|
|
|
|
|
<div class="flex align-center mb-16">
|
2025-06-13 03:02:03 +00:00
|
|
|
<h4 class="medium">{{ currentWorkspace?.name }}</h4>
|
2025-06-26 08:36:08 +00:00
|
|
|
<el-divider direction="vertical" class="mr-8 ml-8" />
|
|
|
|
|
<AppIcon
|
|
|
|
|
iconName="app-workspace"
|
|
|
|
|
style="font-size: 16px"
|
|
|
|
|
class="color-input-placeholder"
|
|
|
|
|
></AppIcon>
|
2025-06-13 03:02:03 +00:00
|
|
|
<span class="color-input-placeholder ml-4">
|
2025-06-13 04:05:56 +00:00
|
|
|
{{ currentWorkspace?.user_count }}
|
2025-06-13 03:02:03 +00:00
|
|
|
</span>
|
|
|
|
|
</div>
|
2025-06-26 08:36:08 +00:00
|
|
|
<Member :currentWorkspace="currentWorkspace" />
|
2025-06-13 03:02:03 +00:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</el-card>
|
|
|
|
|
|
2025-06-26 08:36:08 +00:00
|
|
|
<CreateOrUpdateWorkspaceDialog ref="createOrUpdateWorkspaceDialogRef" @refresh="refresh" />
|
2025-06-13 03:02:03 +00:00
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
<script lang="ts" setup>
|
2025-06-26 08:36:08 +00:00
|
|
|
import { onMounted, ref, watch } from 'vue'
|
2025-06-17 11:22:50 +00:00
|
|
|
import WorkspaceApi from '@/api/workspace/workspace'
|
2025-06-26 08:36:08 +00:00
|
|
|
import { t } from '@/locales'
|
2025-06-13 03:02:03 +00:00
|
|
|
import Member from './component/Member.vue'
|
|
|
|
|
import CreateOrUpdateWorkspaceDialog from './component/CreateOrUpdateWorkspaceDialog.vue'
|
2025-06-26 08:36:08 +00:00
|
|
|
import type { WorkspaceItem } from '@/api/type/workspace'
|
|
|
|
|
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
|
|
|
|
import { PermissionConst, RoleConst } from '@/utils/permission/data'
|
|
|
|
|
import { hasPermission } from '@/utils/permission/index'
|
2025-06-13 03:02:03 +00:00
|
|
|
|
|
|
|
|
const filterText = ref('')
|
|
|
|
|
const loading = ref(false)
|
|
|
|
|
const list = ref<WorkspaceItem[]>([])
|
|
|
|
|
const filterList = ref<WorkspaceItem[]>([]) // 搜索过滤后列表
|
|
|
|
|
const currentWorkspace = ref<WorkspaceItem>()
|
|
|
|
|
|
|
|
|
|
async function getWorkspace() {
|
|
|
|
|
try {
|
|
|
|
|
const res = await WorkspaceApi.getSystemWorkspaceList(loading)
|
|
|
|
|
list.value = res.data
|
|
|
|
|
filterList.value = filter(list.value, filterText.value)
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error(error)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
await getWorkspace()
|
|
|
|
|
currentWorkspace.value = list.value[0]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
async function refresh(workspace?: WorkspaceItem) {
|
2025-06-26 08:36:08 +00:00
|
|
|
await getWorkspace()
|
2025-06-13 03:02:03 +00:00
|
|
|
// 创建角色后选中新建的角色
|
|
|
|
|
currentWorkspace.value = workspace ? workspace : currentWorkspace.value
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function filter(list: WorkspaceItem[], filterText: string) {
|
|
|
|
|
if (!filterText.length) {
|
|
|
|
|
return list
|
|
|
|
|
}
|
2025-06-26 08:36:08 +00:00
|
|
|
return list.filter((v: WorkspaceItem) => v.name.toLowerCase().includes(filterText.toLowerCase()))
|
2025-06-13 03:02:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
watch(filterText, (val: string) => {
|
|
|
|
|
filterList.value = filter(list.value, val)
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
function clickWorkspace(item: WorkspaceItem) {
|
|
|
|
|
currentWorkspace.value = item
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const createOrUpdateWorkspaceDialogRef = ref<InstanceType<typeof CreateOrUpdateWorkspaceDialog>>()
|
2025-06-13 04:05:56 +00:00
|
|
|
|
2025-06-13 03:02:03 +00:00
|
|
|
function createOrUpdateWorkspace(item?: WorkspaceItem) {
|
2025-06-26 08:36:08 +00:00
|
|
|
createOrUpdateWorkspaceDialogRef.value?.open(item)
|
2025-06-13 03:02:03 +00:00
|
|
|
}
|
|
|
|
|
|
2025-06-13 09:38:37 +00:00
|
|
|
async function check(id: string) {
|
|
|
|
|
try {
|
2025-06-26 08:36:08 +00:00
|
|
|
return await WorkspaceApi.deleteWorkspaceCheck(id)
|
2025-06-13 09:38:37 +00:00
|
|
|
} catch (error) {
|
2025-06-26 08:36:08 +00:00
|
|
|
console.log(error)
|
2025-06-13 09:38:37 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function deleteWorkspace(item: WorkspaceItem) {
|
|
|
|
|
// 判断是否能删除
|
2025-06-26 08:36:08 +00:00
|
|
|
const res = await check(item.id as string)
|
|
|
|
|
const canDelete = res ? res.data.can_delete : true
|
2025-06-13 09:38:37 +00:00
|
|
|
if (canDelete) {
|
|
|
|
|
MsgConfirm(
|
|
|
|
|
`${t('views.workspace.delete.confirmTitle')}${item.name} ?`,
|
|
|
|
|
t('views.workspace.delete.confirmContent'),
|
|
|
|
|
{
|
|
|
|
|
confirmButtonText: t('common.confirm'),
|
|
|
|
|
confirmButtonClass: 'danger',
|
|
|
|
|
},
|
2025-06-26 08:36:08 +00:00
|
|
|
).then(() => {
|
|
|
|
|
WorkspaceApi.deleteWorkspace(item.id as string, loading).then(async () => {
|
|
|
|
|
MsgSuccess(t('common.deleteSuccess'))
|
|
|
|
|
await getWorkspace()
|
|
|
|
|
currentWorkspace.value =
|
|
|
|
|
item.id === currentWorkspace.value?.id ? list.value[0] : currentWorkspace.value
|
2025-06-13 03:02:03 +00:00
|
|
|
})
|
2025-06-26 08:36:08 +00:00
|
|
|
})
|
2025-06-13 09:38:37 +00:00
|
|
|
} else {
|
|
|
|
|
MsgConfirm(
|
|
|
|
|
`${t('views.workspace.delete.confirmTitle')}${item.name} ?`,
|
2025-06-23 10:11:31 +00:00
|
|
|
res ? res.data.message : t('views.workspace.delete.confirmContent'),
|
2025-06-13 09:38:37 +00:00
|
|
|
{
|
|
|
|
|
showConfirmButton: false,
|
|
|
|
|
cancelButtonText: t('common.close'),
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
2025-06-13 03:02:03 +00:00
|
|
|
}
|
2025-06-26 08:36:08 +00:00
|
|
|
const mouseId = ref('')
|
|
|
|
|
|
|
|
|
|
function mouseenter(row: any) {
|
|
|
|
|
mouseId.value = row.id
|
|
|
|
|
}
|
2025-06-13 03:02:03 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
2025-06-26 08:36:08 +00:00
|
|
|
.workspace-manage {
|
2025-06-13 03:02:03 +00:00
|
|
|
.workspace-left {
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
width: var(--setting-left-width);
|
|
|
|
|
min-width: var(--setting-left-width);
|
|
|
|
|
|
|
|
|
|
.list-height-left {
|
|
|
|
|
height: calc(100vh - 255px);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.workspace-right {
|
|
|
|
|
flex: 1;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</style>
|