Recycled files action

This commit is contained in:
2025-07-27 12:30:13 +08:00
parent e7e6c258e2
commit 4c0e0b5ee9
5 changed files with 192 additions and 11 deletions

View File

@@ -8,8 +8,8 @@
value-field="id"
label-field="name"
:placeholder="props.placeholder || 'Select a file pool to upload'"
:size="props.size || 'large'"
clearable
size="large"
/>
</template>
@@ -29,6 +29,7 @@ import { formatBytes } from '@/views/format'
const props = defineProps<{
modelValue: string | null
placeholder?: string | undefined
size?: 'tiny' | 'small' | 'medium' | 'large' | undefined
}>()
const emit = defineEmits(['update:modelValue', 'update:pool'])

View File

@@ -1,12 +1,30 @@
<template>
<section class="h-full px-5 py-4">
<div class="flex flex-col gap-3 mb-3">
<div class="flex items-center gap-4 mb-3">
<file-pool-select
v-model="filePool"
placeholder="Filter by file pool"
size="medium"
class="max-w-[480px]"
@update:pool="fetchFiles"
/>
<div class="flex items-center gap-2.5">
<n-switch size="large" v-model:value="showRecycled">
<template #checked>Recycled</template>
<template #unchecked>Unrecycled</template>
</n-switch>
<n-button
@click="askDeleteRecycledFiles"
v-if="showRecycled"
type="error"
circle
size="small"
>
<n-icon>
<delete-sweep-round />
</n-icon>
</n-button>
</div>
</div>
<n-data-table
remote
@@ -32,6 +50,8 @@ import {
useDialog,
useMessage,
useLoadingBar,
NSwitch,
NTooltip,
} from 'naive-ui'
import {
AudioFileRound,
@@ -39,8 +59,9 @@ import {
VideoFileRound,
FileDownloadOutlined,
DeleteRound,
DeleteSweepRound,
} from '@vicons/material'
import { h, onMounted, ref } from 'vue'
import { h, onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router'
import { formatBytes } from '../format'
import FilePoolSelect from '@/components/FilePoolSelect.vue'
@@ -48,7 +69,9 @@ import FilePoolSelect from '@/components/FilePoolSelect.vue'
const router = useRouter()
const files = ref<any[]>([])
const filePool = ref<string | null>(null)
const showRecycled = ref(false)
const tableColumns: DataTableColumns<any> = [
{
@@ -98,6 +121,28 @@ const tableColumns: DataTableColumns<any> = [
return formatBytes(row.size)
},
},
{
title: 'Pool',
key: 'pool',
render(row: any) {
return h(
NTooltip,
{},
{
default: () => h('span', row.pool.id),
trigger: () => h('span', row.pool.name),
},
)
},
},
{
title: 'Expired At',
key: 'expired_at',
render(row: any) {
if (!row.expired_at) return 'Keep-alive'
return new Date(row.expired_at).toLocaleString()
},
},
{
title: 'Uploaded At',
key: 'created_at',
@@ -156,7 +201,7 @@ async function fetchFiles() {
loading.value = true
const pag = tablePagination.value
const response = await fetch(
`/api/files/me?take=${pag.pageSize}&offset=${(pag.page! - 1) * pag.pageSize!}${filePool.value ? '&pool=' + filePool.value : ''}`,
`/api/files/me?take=${pag.pageSize}&offset=${(pag.page! - 1) * pag.pageSize!}&recycled=${showRecycled.value}${filePool.value ? '&pool=' + filePool.value : ''}`,
)
if (!response.ok) {
throw new Error('Network response was not ok')
@@ -172,6 +217,12 @@ async function fetchFiles() {
}
onMounted(() => fetchFiles())
watch(showRecycled, () => {
tablePagination.value.itemCount = 0
tablePagination.value.page = 1
fetchFiles()
})
function handlePageChange(page: number) {
tablePagination.value.page = page
fetchFiles()
@@ -183,10 +234,10 @@ const dialog = useDialog()
const messageDialog = useMessage()
const loadingBar = useLoadingBar()
async function askDeleteFile(file: any) {
function askDeleteFile(file: any) {
dialog.warning({
title: 'Confirm',
content: `Are you sure you want delete ${file.name}?`,
content: `Are you sure you want delete ${file.name}? This will delete the stored file data immediately, there is no return.`,
positiveText: 'Sure',
negativeText: 'Not Sure',
draggable: true,
@@ -214,4 +265,37 @@ async function deleteFile(file: any) {
messageDialog.error('Failed to delete file: ' + (error as Error).message)
}
}
function askDeleteRecycledFiles() {
dialog.warning({
title: 'Confirm',
content: `Are you sure you want to delete all ${tablePagination.value.itemCount} marked recycled file(s) by system?`,
positiveText: 'Sure',
negativeText: 'Not Sure',
draggable: true,
onPositiveClick: () => {
deleteRecycledFiles()
},
})
}
async function deleteRecycledFiles() {
try {
loadingBar.start()
const response = await fetch('/api/files/me/recycle', {
method: 'DELETE',
})
if (!response.ok) {
throw new Error('Network response was not ok')
}
const resp = await response.json()
tablePagination.value.page = 1
await fetchFiles()
loadingBar.finish()
messageDialog.success(`Recycled files deleted successfully, deleted count: ${resp.count}`)
} catch (error) {
loadingBar.error()
messageDialog.error('Failed to delete recycled files: ' + (error as Error).message)
}
}
</script>