fix: fix storage file
This commit is contained in:
4
bo/components.d.ts
vendored
4
bo/components.d.ts
vendored
@@ -13,7 +13,9 @@ declare module 'vue' {
|
|||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
ButtonGoToProfile: typeof import('./src/components/customer-management/ButtonGoToProfile.vue')['default']
|
ButtonGoToProfile: typeof import('./src/components/customer-management/ButtonGoToProfile.vue')['default']
|
||||||
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
|
CartDetails: typeof import('./src/components/customer/CartDetails.vue')['default']
|
||||||
CategoryMenu: typeof import('./src/components/inner/categoryMenu.vue')['default']
|
CategoryMenu: typeof import('./src/components/inner/CategoryMenu.vue')['default']
|
||||||
|
copy: typeof import('./src/components/admin/ProductDetailView copy.vue')['default']
|
||||||
|
CountryCurrencySwitch: typeof import('./src/components/inner/CountryCurrencySwitch.vue')['default']
|
||||||
Cs_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
|
Cs_PrivacyPolicyView: typeof import('./src/components/terms/cs_PrivacyPolicyView.vue')['default']
|
||||||
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.vue')['default']
|
Cs_TermsAndConditionsView: typeof import('./src/components/terms/cs_TermsAndConditionsView.vue')['default']
|
||||||
En_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
|
En_PrivacyPolicyView: typeof import('./src/components/terms/en_PrivacyPolicyView.vue')['default']
|
||||||
|
|||||||
@@ -1,27 +1,37 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="Default || 'div'">
|
<component :is="Default || 'div'">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
|
|
||||||
<div v-if="loading" class="flex justify-center py-8">
|
<div v-if="loading" class="flex justify-center py-8">
|
||||||
<ULoader />
|
<ULoader />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="error" class="text-red-500">
|
<div v-else-if="error" class="text-red-500">
|
||||||
{{ error }}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
<UTree v-else :items="treeItems" :expanded="expandedFolders">
|
|
||||||
|
<UTree v-if="showTree" :items="treeItems" v-model:expanded="expandedFolders" :key="treeKey" @toggle="onToggle" :get-key="item => item.value">
|
||||||
<template #item-wrapper="{ item }">
|
<template #item-wrapper="{ item }">
|
||||||
<div class="flex items-start cursor-pointer" @click="onItemClick(item)">
|
<div class="flex items-start cursor-pointer">
|
||||||
|
|
||||||
<div class="flex items-center gap-1">
|
<div class="flex items-center gap-1">
|
||||||
<UIcon :name="item.icon" :size="30" />
|
<UIcon :name="item.icon" :size="30" />
|
||||||
|
|
||||||
<div class="flex gap-1 items-center">
|
<div class="flex gap-1 items-center">
|
||||||
<span class="text-[15px] font-medium">{{ item.label }}</span>
|
<span class="text-[15px] font-medium">
|
||||||
|
{{ item.label }}
|
||||||
|
</span>
|
||||||
|
|
||||||
<UButton v-if="!item.isFolder && item.fileName" size="xxs" color="neutral"
|
<UButton v-if="!item.isFolder && item.fileName" size="xxs" color="neutral"
|
||||||
variant="outline" icon="i-lucide-download"
|
variant="outline" icon="i-lucide-download"
|
||||||
@click.stop="downloadFile(item.path, item.fileName)" :ui="{ base: 'ring-0!' }" />
|
@click.stop="downloadFile(item.path, item.fileName)" :ui="{ base: 'ring-0!' }" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</UTree>
|
</UTree>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
@@ -54,106 +64,106 @@ interface TreeItem {
|
|||||||
const props = defineProps<{ initialPath?: string }>()
|
const props = defineProps<{ initialPath?: string }>()
|
||||||
|
|
||||||
const currentPath = ref(props.initialPath || '')
|
const currentPath = ref(props.initialPath || '')
|
||||||
const allData = ref<Map<string, FileItem[]>>(new Map())
|
|
||||||
|
const allData = ref<Record<string, FileItem[]>>({})
|
||||||
const expandedFolders = ref<string[]>([])
|
const expandedFolders = ref<string[]>([])
|
||||||
|
const treeKey = ref(0)
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const error = ref<string | null>(null)
|
const error = ref<string | null>(null)
|
||||||
|
|
||||||
|
const showTree = computed(() => !error.value)
|
||||||
|
|
||||||
async function fetchFolderContents(path: string): Promise<FileItem[]> {
|
async function fetchFolderContents(path: string): Promise<FileItem[]> {
|
||||||
const url = `/api/v1/restricted/storage/list-content/${path}`
|
const url = `/api/v1/restricted/storage/list-content/${path}`
|
||||||
const data = await useFetchJson<FileItemRaw[]>(url)
|
const data = await useFetchJson<FileItemRaw[]>(url)
|
||||||
|
|
||||||
return (data.items || []).map(i => ({
|
return (data.items || []).map(i => ({
|
||||||
name: i.Name,
|
name: i.Name,
|
||||||
type: i.IsFolder ? 'folder' : 'file'
|
type: i.IsFolder ? 'folder' : 'file'
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function loadFolder(path: string) {
|
async function loadFolder(path: string) {
|
||||||
if (allData.value.has(path)) return
|
if (allData.value[path]) return
|
||||||
loading.value = true
|
|
||||||
error.value = null
|
|
||||||
try {
|
try {
|
||||||
const items = await fetchFolderContents(path)
|
const items = await fetchFolderContents(path)
|
||||||
allData.value.set(path, items)
|
allData.value[path] = items
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = e instanceof Error ? e.message : 'Failed to load folder contents'
|
error.value = e instanceof Error ? e.message : 'Failed to load folder contents'
|
||||||
} finally {
|
|
||||||
loading.value = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildTree(path: string): TreeItem[] {
|
||||||
|
const items = allData.value[path] || []
|
||||||
|
|
||||||
async function toggleFolder(item: TreeItem) {
|
|
||||||
if (!item.isFolder) return
|
|
||||||
|
|
||||||
if (!expandedFolders.value.includes(item.value)) {
|
|
||||||
expandedFolders.value.push(item.value)
|
|
||||||
await loadFolder(item.value)
|
|
||||||
} else {
|
|
||||||
expandedFolders.value = expandedFolders.value.filter(v => v !== item.value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onItemClick(item: TreeItem) {
|
|
||||||
if (item.isFolder) {
|
|
||||||
toggleFolder(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function buildTreeItems(items: FileItem[], path: string): TreeItem[] {
|
|
||||||
return items.map(item => {
|
return items.map(item => {
|
||||||
const itemPath = path ? `${path}/${item.name}` : item.name
|
const itemPath = path ? `${path}/${item.name}` : item.name
|
||||||
const isFolder = item.type === 'folder'
|
const isFolder = item.type === 'folder'
|
||||||
|
|
||||||
const children = isFolder
|
const isExpanded = expandedFolders.value.includes(itemPath)
|
||||||
? buildTreeItems(allData.value.get(itemPath) || [], itemPath)
|
const isLoaded = !!allData.value[itemPath]
|
||||||
: undefined
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
label: item.name,
|
label: item.name,
|
||||||
|
|
||||||
icon: isFolder ? 'fxemoji:folder' : 'flat-color-icons:file',
|
icon: isFolder ? 'fxemoji:folder' : 'flat-color-icons:file',
|
||||||
isFolder,
|
isFolder,
|
||||||
path: isFolder ? itemPath : path,
|
path: isFolder ? itemPath : path,
|
||||||
value: itemPath,
|
value: itemPath,
|
||||||
fileName: isFolder ? undefined : item.name,
|
fileName: isFolder ? undefined : item.name,
|
||||||
children
|
|
||||||
|
children: isFolder && isExpanded && isLoaded
|
||||||
|
? buildTree(itemPath)
|
||||||
|
: []
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const treeItems = computed(() => buildTree(currentPath.value))
|
||||||
|
|
||||||
|
async function toggleFolder(item: TreeItem) {
|
||||||
|
if (!item.isFolder) return
|
||||||
|
|
||||||
|
const isOpen = expandedFolders.value.includes(item.value)
|
||||||
|
|
||||||
|
if (!isOpen) {
|
||||||
|
await loadFolder(item.value)
|
||||||
|
treeKey.value++
|
||||||
|
} else {
|
||||||
|
treeKey.value++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onToggle(_event: unknown, item: TreeItem) {
|
||||||
|
console.log('Toggle:', item)
|
||||||
|
if (item.isFolder) {
|
||||||
|
toggleFolder(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function downloadFile(path: string, fileName: string) {
|
async function downloadFile(path: string, fileName: string) {
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/v1/restricted/storage/download-file/${path}/${fileName}`)
|
const response = await fetch(`/api/v1/restricted/storage/download-file/${path}/${fileName}`)
|
||||||
if (!response.ok) throw new Error('Failed to download file')
|
if (!response.ok) throw new Error('Download failed')
|
||||||
|
|
||||||
const blob = await response.blob()
|
const blob = await response.blob()
|
||||||
const url = window.URL.createObjectURL(blob)
|
const url = window.URL.createObjectURL(blob)
|
||||||
|
|
||||||
const a = document.createElement('a')
|
const a = document.createElement('a')
|
||||||
a.href = url
|
a.href = url
|
||||||
a.download = fileName
|
a.download = fileName
|
||||||
|
|
||||||
document.body.appendChild(a)
|
document.body.appendChild(a)
|
||||||
a.click()
|
a.click()
|
||||||
a.remove()
|
a.remove()
|
||||||
|
|
||||||
window.URL.revokeObjectURL(url)
|
window.URL.revokeObjectURL(url)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Download error:', e)
|
console.error(e)
|
||||||
alert('Failed to download file')
|
alert('Download failed')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const treeItems = computed<TreeItem[]>(() => {
|
loadFolder(currentPath.value)
|
||||||
const items = allData.value.get(currentPath.value) || []
|
|
||||||
return buildTreeItems(items, currentPath.value)
|
|
||||||
})
|
|
||||||
|
|
||||||
loadFolder(currentPath.value).then(() => {
|
|
||||||
const rootItems = treeItems.value
|
|
||||||
if (rootItems.length > 0 && rootItems[0].isFolder) {
|
|
||||||
toggleFolder(rootItems[0])
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
Reference in New Issue
Block a user