feat: add admin detail policy actions

This commit is contained in:
Lan
2026-06-03 05:45:02 +08:00
parent f446062272
commit 3ab44b3cce
6 changed files with 273 additions and 1 deletions
+162 -1
View File
@@ -13,6 +13,8 @@ import type {
AdminFileInsightSeverity,
AdminFilePatchPayload,
AdminFileListParams,
AdminFilePolicyAction,
AdminFilePolicyActionRequest,
AdminFileStatusFilter,
AdminFileSummary,
AdminFileTypeFilter,
@@ -61,6 +63,14 @@ const isLegacyEndpointUnavailable = (error: unknown) => {
}
const legacyForeverExpiresAt = '2099-12-31T23:59'
const detailPolicyDownloadLimit = 5
const dayInMilliseconds = 24 * 60 * 60 * 1000
type DetailPolicyActionOption = {
action: AdminFilePolicyAction
label: string
description: string
}
const emptyBatchEditForm = (): AdminBatchEditForm => ({
mode: 'expiresAt',
@@ -68,6 +78,18 @@ const emptyBatchEditForm = (): AdminBatchEditForm => ({
expired_count: null
})
const padDatePart = (value: number) => String(value).padStart(2, '0')
const formatLocalDateTime = (date: Date) => {
const year = date.getFullYear()
const month = padDatePart(date.getMonth() + 1)
const day = padDatePart(date.getDate())
const hours = padDatePart(date.getHours())
const minutes = padDatePart(date.getMinutes())
return `${year}-${month}-${day}T${hours}:${minutes}`
}
export function useAdminFiles() {
const { t } = useI18n()
const alertStore = useAlertStore()
@@ -108,6 +130,7 @@ export function useAdminFiles() {
const showFileDetailModal = ref(false)
const selectedFileDetail = ref<AdminFileDetailViewItem | null>(null)
const isDetailLoading = ref(false)
const isDetailPolicyActionRunning = ref(false)
const downloadingFileId = ref<number | null>(null)
const selectedFileIds = ref<Set<number>>(new Set())
const isBatchDeleting = ref(false)
@@ -145,6 +168,33 @@ export function useAdminFiles() {
params.value.type !== 'all'
)
const detailPolicyActionOptions = computed<DetailPolicyActionOption[]>(() => [
{
action: 'extend_24h',
label: t('fileManage.policyActions.extend24h'),
description: t('fileManage.policyActionDescriptions.extend24h')
},
{
action: 'extend_7d',
label: t('fileManage.policyActions.extend7d'),
description: t('fileManage.policyActionDescriptions.extend7d')
},
{
action: 'make_permanent',
label: t('fileManage.policyActions.makePermanent'),
description: t('fileManage.policyActionDescriptions.makePermanent')
},
{
action: 'reset_download_limit',
label: t('fileManage.policyActions.resetDownloadLimit', {
count: detailPolicyDownloadLimit
}),
description: t('fileManage.policyActionDescriptions.resetDownloadLimit', {
count: detailPolicyDownloadLimit
})
}
])
const inferIsText = (file: FileListItem) => {
if (typeof file.isText === 'boolean') return file.isText
if (typeof file.is_text === 'boolean') return file.is_text
@@ -158,7 +208,7 @@ export function useAdminFiles() {
if (
file.expired_count !== null &&
file.expired_count !== undefined &&
file.expired_count <= 0
file.expired_count === 0
) {
return true
}
@@ -463,6 +513,84 @@ export function useAdminFiles() {
return patchPayload
}
const buildPolicyActionRequest = (
file: AdminFileDetailViewItem,
action: AdminFilePolicyAction
): AdminFilePolicyActionRequest => {
const request: AdminFilePolicyActionRequest = {
id: file.id,
action
}
if (action === 'reset_download_limit') {
request.downloadLimit = detailPolicyDownloadLimit
request.download_limit = detailPolicyDownloadLimit
}
return request
}
const getPolicyActionBaseDate = (file: AdminFileDetailViewItem) => {
const now = new Date()
const expiredAt = file.expired_at ? new Date(file.expired_at) : null
if (!expiredAt || Number.isNaN(expiredAt.getTime()) || expiredAt.getTime() < now.getTime()) {
return now
}
return expiredAt
}
const buildLegacyPolicyActionPayload = (
file: AdminFileDetailViewItem,
action: AdminFilePolicyAction
): AdminFilePatchPayload => {
if (action === 'make_permanent') {
return {
id: file.id,
expired_at: legacyForeverExpiresAt,
expired_count: -1
}
}
if (action === 'reset_download_limit') {
return {
id: file.id,
expired_count: detailPolicyDownloadLimit
}
}
const offsetDays = action === 'extend_7d' ? 7 : 1
const nextExpiredAt = new Date(
getPolicyActionBaseDate(file).getTime() + offsetDays * dayInMilliseconds
)
return {
id: file.id,
expired_at: formatLocalDateTime(nextExpiredAt)
}
}
const refreshSelectedFileDetail = async (fileId: number, detail?: AdminFileDetailResponse) => {
if (detail) {
selectedFileDetail.value = createFileDetailViewItem(detail)
return
}
const fallbackFile = tableData.value.find((file) => file.id === fileId)
if (fallbackFile) {
selectedFileDetail.value = createFileDetailViewItem(fallbackFile)
}
try {
const response = await FileService.getAdminFileDetail(fileId)
if (response.detail) {
selectedFileDetail.value = createFileDetailViewItem(response.detail)
}
} catch (error: unknown) {
if (!isLegacyEndpointUnavailable(error)) {
throw error
}
}
}
const loadFiles = async () => {
isLoading.value = true
try {
@@ -775,6 +903,36 @@ export function useAdminFiles() {
}
}
const applyDetailPolicyAction = async (action: AdminFilePolicyAction) => {
const file = selectedFileDetail.value
if (!file || isDetailPolicyActionRunning.value) return
isDetailPolicyActionRunning.value = true
try {
let nextDetail: AdminFileDetailResponse | undefined
try {
const response = await FileService.applyAdminFilePolicyAction(
buildPolicyActionRequest(file, action)
)
nextDetail = response.detail
} catch (error: unknown) {
if (!isLegacyEndpointUnavailable(error)) {
throw error
}
await FileService.updateFile(buildLegacyPolicyActionPayload(file, action))
}
await loadFiles()
await refreshSelectedFileDetail(file.id, nextDetail)
alertStore.showAlert(t('fileManage.policyActionSuccess'), 'success')
} catch (error: unknown) {
alertStore.showAlert(getErrorMessage(error, t('fileManage.policyActionFailed')), 'error')
} finally {
isDetailPolicyActionRunning.value = false
}
}
const closeFileDetail = () => {
detailRequestSerial += 1
showFileDetailModal.value = false
@@ -846,9 +1004,11 @@ export function useAdminFiles() {
isBatchUpdating,
isCurrentPagePartiallySelected,
isDetailLoading,
isDetailPolicyActionRunning,
isPreviewLoading,
isSaving,
batchEditForm,
detailPolicyActionOptions,
downloadingFileId,
hasSelectedFiles,
params,
@@ -880,6 +1040,7 @@ export function useAdminFiles() {
exportPreviewText,
handlePageChange,
handleSearch,
applyDetailPolicyAction,
handleBatchUpdate,
handleUpdate,
loadFiles,