You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
4.6 KiB
192 lines
4.6 KiB
<script setup lang="ts">
|
|
import type { EventDataNode, Key } from 'ant-design-vue/es/vc-tree/interface';
|
|
import type { TreeProps } from 'ant-design-vue/es/vc-tree/props';
|
|
|
|
import type { OssContainerDto } from '../../types';
|
|
import type { OssObjectDto } from '../../types/objects';
|
|
|
|
import { defineAsyncComponent, onMounted, ref } from 'vue';
|
|
|
|
import { useVbenModal } from '@vben/common-ui';
|
|
import { $t } from '@vben/locales';
|
|
|
|
import { Button, Card, DirectoryTree, Empty, Select } from 'ant-design-vue';
|
|
|
|
import { useContainesApi } from '../../api';
|
|
|
|
const emits = defineEmits<{
|
|
(event: 'bucketChange', data: string): void;
|
|
(event: 'folderChange', data: string): void;
|
|
}>();
|
|
|
|
interface Folder {
|
|
children?: Folder[];
|
|
isLeaf?: boolean;
|
|
key: string;
|
|
name: string;
|
|
path?: string;
|
|
title: string;
|
|
}
|
|
|
|
const { getListApi: getContainersApi, getObjectsApi } = useContainesApi();
|
|
|
|
const [FolderModal, modalApi] = useVbenModal({
|
|
connectedComponent: defineAsyncComponent(() => import('./FolderModal.vue')),
|
|
});
|
|
|
|
const rootFolder: Folder = {
|
|
isLeaf: false,
|
|
key: './',
|
|
name: './',
|
|
path: '',
|
|
title: $t('AbpOssManagement.Objects:Root'),
|
|
children: [],
|
|
};
|
|
|
|
const bucket = ref<string>('');
|
|
const loadedFolders = ref<string[]>([]);
|
|
const expandedFolders = ref<string[]>([]);
|
|
const selectedFolders = ref<string[]>([]);
|
|
const containers = ref<OssContainerDto[]>([]);
|
|
const folders = ref<Folder[]>([
|
|
{
|
|
...rootFolder,
|
|
},
|
|
]);
|
|
|
|
const onLoadChildFolders: TreeProps['loadData'] = async (treeNode) => {
|
|
let path = '';
|
|
if (treeNode.dataRef?.path) {
|
|
path = path + treeNode.dataRef?.path;
|
|
}
|
|
if (treeNode.dataRef?.name) {
|
|
path = path + treeNode.dataRef?.name;
|
|
}
|
|
try {
|
|
treeNode.dataRef!.children = await getFolders(bucket.value!, path);
|
|
} catch {
|
|
treeNode.dataRef!.children = [];
|
|
}
|
|
folders.value = [...folders.value];
|
|
loadedFolders.value = [...loadedFolders.value, treeNode.key.toString()];
|
|
};
|
|
|
|
async function onInit() {
|
|
const getContainersRes = await getContainersApi({
|
|
maxResultCount: 1000,
|
|
});
|
|
containers.value = getContainersRes.containers;
|
|
}
|
|
|
|
async function getFolders(bucket: string, path?: string) {
|
|
const { objects } = await getObjectsApi({
|
|
bucket,
|
|
delimiter: '/',
|
|
maxResultCount: 1000,
|
|
prefix: path ?? '',
|
|
});
|
|
return objects
|
|
.filter((f) => f.isFolder)
|
|
.map((folder) => {
|
|
return {
|
|
isLeaf: false,
|
|
key: `${folder.path ?? ''}${folder.name}`,
|
|
name: folder.name,
|
|
path: folder.path,
|
|
title: folder.name,
|
|
children: [],
|
|
};
|
|
});
|
|
}
|
|
|
|
function onFolderExpand(
|
|
_: Key[],
|
|
info: {
|
|
expanded: boolean;
|
|
node: EventDataNode;
|
|
},
|
|
) {
|
|
if (!info.expanded) {
|
|
const keys = loadedFolders.value;
|
|
const findIndex = keys.lastIndexOf(info.node.key.toString());
|
|
findIndex !== -1 && keys.splice(findIndex);
|
|
loadedFolders.value = keys;
|
|
}
|
|
}
|
|
|
|
function onFolderChange(selectedKeys: Key[]) {
|
|
if (selectedKeys.length === 1) {
|
|
emits('folderChange', selectedKeys[0]!.toString());
|
|
}
|
|
}
|
|
|
|
async function onBucketChange(bucket: string) {
|
|
emits('bucketChange', bucket);
|
|
expandedFolders.value = [];
|
|
loadedFolders.value = [];
|
|
folders.value = [
|
|
{
|
|
...rootFolder,
|
|
},
|
|
];
|
|
}
|
|
|
|
function onCreate() {
|
|
modalApi.setData({
|
|
bucket: bucket.value,
|
|
path: selectedFolders.value[0],
|
|
});
|
|
modalApi.open();
|
|
}
|
|
|
|
function onFolderCreated(ossObject: OssObjectDto) {
|
|
const keys = expandedFolders.value;
|
|
const findIndex = keys.lastIndexOf(ossObject.path);
|
|
if (findIndex !== -1) {
|
|
keys.splice(findIndex);
|
|
expandedFolders.value = keys;
|
|
loadedFolders.value = [];
|
|
}
|
|
}
|
|
|
|
onMounted(onInit);
|
|
</script>
|
|
|
|
<template>
|
|
<Card :title="$t('AbpOssManagement.Containers')">
|
|
<div class="flex flex-col gap-2">
|
|
<Select
|
|
:placeholder="$t('AbpOssManagement.Containers:Select')"
|
|
:options="containers"
|
|
:field-names="{ label: 'name', value: 'name' }"
|
|
v-model:value="bucket"
|
|
@change="(e) => onBucketChange(e!.toString())"
|
|
/>
|
|
<Button v-if="bucket" block type="primary" ghost @click="onCreate">
|
|
{{ $t('AbpOssManagement.Objects:CreateFolder') }}
|
|
</Button>
|
|
<DirectoryTree
|
|
v-if="bucket"
|
|
block-node
|
|
v-model:expanded-keys="expandedFolders"
|
|
v-model:selected-keys="selectedFolders"
|
|
:loaded-keys="loadedFolders"
|
|
:tree-data="folders"
|
|
:load-data="onLoadChildFolders"
|
|
@select="onFolderChange"
|
|
@expand="onFolderExpand"
|
|
/>
|
|
<Empty v-else />
|
|
</div>
|
|
</Card>
|
|
<FolderModal @change="onFolderCreated" />
|
|
</template>
|
|
|
|
<style scoped lang="scss">
|
|
:deep(.ant-tree) {
|
|
.ant-tree-title {
|
|
word-break: break-word;
|
|
white-space: normal;
|
|
}
|
|
}
|
|
</style>
|
|
|