refactor(system/file): 重构文件管理相关代码

This commit is contained in:
2025-05-15 23:18:02 +08:00
parent dc66e9e62c
commit b680ee3fac
11 changed files with 55 additions and 62 deletions

View File

@@ -32,5 +32,5 @@ export function checkFile(sha256: string) {
/** @desc 创建文件夹 */ /** @desc 创建文件夹 */
export function createDir(path: string, name: string) { export function createDir(path: string, name: string) {
return http.post<T.FileItem>(`${BASE_URL}/createDir`, { parentPath: path, name }) return http.post<T.FileItem>(`${BASE_URL}/dir`, { path, originalName: name })
} }

View File

@@ -202,24 +202,25 @@ export interface NoticePageQuery extends NoticeQuery, PageQuery {
export interface FileItem { export interface FileItem {
id: string id: string
name: string name: string
originalName: string
size: number size: number
url: string url: string
parentPath: string path: string
absPath: string
metadata: string
sha256: string sha256: string
contentType: string contentType: string
metadata: string
thumbnailSize: number thumbnailSize: number
thumbnailUrl: string thumbnailName: string
thumbnailMetadata: string thumbnailMetadata: string
thumbnailUrl: string
extension: string extension: string
type: number type: number
storageId: string storageId: string
storageName: string storageName: string
createUserString: string createUserString: string
createTime: string createTime: string
updateUserString: string updateUserString?: string
updateTime: string updateTime?: string
} }
/** 文件资源统计信息 */ /** 文件资源统计信息 */
export interface FileStatisticsResp { export interface FileStatisticsResp {
@@ -230,9 +231,9 @@ export interface FileStatisticsResp {
data: Array<FileStatisticsResp> data: Array<FileStatisticsResp>
} }
export interface FileQuery { export interface FileQuery {
name?: string originalName?: string
type?: string type?: string
absPath?: string path?: string
sort: Array<string> sort: Array<string>
} }
export interface FilePageQuery extends FileQuery, PageQuery { export interface FilePageQuery extends FileQuery, PageQuery {

View File

@@ -101,7 +101,7 @@ const columns: ColumnItem[] = reactive([
field: 'domain', field: 'domain',
type: 'input', type: 'input',
span: 24, span: 24,
required: true, required: false,
show: () => form.type === 2, show: () => form.type === 2,
}, },
{ {

View File

@@ -5,7 +5,7 @@
<div ref="audioHeadRef" class="audio-box__header"> <div ref="audioHeadRef" class="audio-box__header">
<div class="audio-name"> <div class="audio-name">
<icon-music :size="16" spin /> <icon-music :size="16" spin />
<span>{{ props.data?.name }}.{{ props.data?.extension }}</span> <span>{{ props.data?.originalName }}</span>
</div> </div>
<div class="close-icon" @click="close"> <div class="close-icon" @click="close">
<icon-close :size="12" /> <icon-close :size="12" />

View File

@@ -9,14 +9,19 @@
<a-descriptions-item label="名称"> <a-descriptions-item label="名称">
<a-typography-paragraph copyable :copy-text="data.url"> <a-typography-paragraph copyable :copy-text="data.url">
<template #copy-tooltip>复制链接</template> <template #copy-tooltip>复制链接</template>
{{ getFileName(data) }} {{ data.originalName }}
</a-typography-paragraph> </a-typography-paragraph>
</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item label="大小">{{ formatFileSize(data.size) }}</a-descriptions-item> <a-descriptions-item label="大小">{{ formatFileSize(data.size) }}</a-descriptions-item>
<a-descriptions-item label="路径">{{ data.absPath + getFileName(data) }}</a-descriptions-item> <a-descriptions-item label="路径">{{ `${data.path === '/' ? '' : data.path}/${data.name}` }}</a-descriptions-item>
<a-descriptions-item label="SHA256">{{ data.sha256 }}</a-descriptions-item> <a-descriptions-item v-if="data.sha256" label="SHA256">
<a-typography-paragraph copyable :copy-text="data.sha256">
<template #copy-tooltip>复制</template>
{{ data.sha256 }}
</a-typography-paragraph>
</a-descriptions-item>
<a-descriptions-item label="上传时间">{{ data.createTime }}</a-descriptions-item> <a-descriptions-item label="上传时间">{{ data.createTime }}</a-descriptions-item>
<a-descriptions-item label="修改时间">{{ data.updateTime }}</a-descriptions-item> <a-descriptions-item v-if="data?.updateTime" label="修改时间">{{ data?.updateTime }}</a-descriptions-item>
<a-descriptions-item label="存储名称">{{ data.storageName }}</a-descriptions-item> <a-descriptions-item label="存储名称">{{ data.storageName }}</a-descriptions-item>
</a-descriptions> </a-descriptions>
</a-row> </a-row>
@@ -32,11 +37,6 @@ interface Props {
} }
withDefaults(defineProps<Props>(), {}) withDefaults(defineProps<Props>(), {})
// 文件名称带后缀
const getFileName = (item: FileItem) => {
return `${item.name}${item.extension ? `.${item.extension}` : ''}`
}
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@@ -3,11 +3,11 @@
<a-form ref="formRef" :model="form" auto-label-width class="w-full"> <a-form ref="formRef" :model="form" auto-label-width class="w-full">
<a-form-item <a-form-item
label="文件名称" label="文件名称"
field="name" field="originalName"
:rules="[{ required: true, message: '请输入文件名称' }]" :rules="[{ required: true, message: '请输入文件名称' }]"
style="margin-bottom: 0" style="margin-bottom: 0"
> >
<a-input v-model="form.name" placeholder="请输入文件名称" allow-clear /> <a-input v-model="form.originalName" placeholder="请输入文件名称" allow-clear />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-row> </a-row>
@@ -24,7 +24,7 @@ const props = withDefaults(defineProps<Props>(), {})
const formRef = ref<FormInstance>() const formRef = ref<FormInstance>()
const form = reactive({ const form = reactive({
name: props.data?.name || '', originalName: props.data?.originalName || '',
}) })
defineExpose({ formRef }) defineExpose({ formRef })

View File

@@ -21,7 +21,7 @@ export function openFileRenameModal(data: FileItem, callback?: () => void) {
const isInvalid = await ModalContentRef.value?.formRef?.validate() const isInvalid = await ModalContentRef.value?.formRef?.validate()
const modelParams = ModalContentRef.value?.formRef?.model const modelParams = ModalContentRef.value?.formRef?.model
if (isInvalid) return false if (isInvalid) return false
await updateFile({ name: modelParams?.name }, data.id) await updateFile({ originalName: modelParams?.originalName }, data.id)
Message.success('重命名成功') Message.success('重命名成功')
if (callback) { if (callback) {
callback() callback()

View File

@@ -16,9 +16,9 @@
<div class="file-grid-item" @click.stop="handleClickFile(item)" @dblclick="handleDblclickFile(item)"> <div class="file-grid-item" @click.stop="handleClickFile(item)" @dblclick="handleDblclickFile(item)">
<section class="file-grid-item__wrapper"> <section class="file-grid-item__wrapper">
<div class="file-icon"> <div class="file-icon">
<FileImage :data="item" :title="item.name"></FileImage> <FileImage :data="item" :title="item.originalName"></FileImage>
</div> </div>
<p class="gi_line_1 file-name">{{ getFileName(item) }}</p> <p class="gi_line_1 file-name">{{ item.originalName }}</p>
</section> </section>
<!-- 勾选模式 --> <!-- 勾选模式 -->
<section <section
@@ -64,11 +64,6 @@ interface Props {
isBatchMode?: boolean isBatchMode?: boolean
} }
// 文件名称带后缀
const getFileName = (item: FileItem) => {
return `${item.name}${item.extension ? `.${item.extension}` : ''}`
}
// 点击事件 // 点击事件
const handleClickFile = (item: FileItem) => { const handleClickFile = (item: FileItem) => {
emit('click', item) emit('click', item)

View File

@@ -15,13 +15,17 @@ const props = withDefaults(defineProps<Props>(), {})
// 是否是图片类型文件 // 是否是图片类型文件
const isImage = computed(() => { const isImage = computed(() => {
const extension = props.data.extension.toLowerCase() const extension = props.data.extension?.toLowerCase()
return ImageTypes.includes(extension) return ImageTypes.includes(extension)
}) })
// 获取文件图标,如果是图片就显示图片 // 获取文件图标,如果是图片就显示图片
const getFileImg = computed<string>(() => { const getFileImg = computed<string>(() => {
const extension = props.data.extension.toLowerCase() // 文件夹
if (props.data.type === 0) {
return FileIcon.dir
}
const extension = props.data.extension?.toLowerCase()
if (ImageTypes.includes(extension)) { if (ImageTypes.includes(extension)) {
return props.data.url || '' return props.data.url || ''
} }

View File

@@ -30,7 +30,7 @@
</div> </div>
<a-typography-paragraph copyable :copy-text="record.url"> <a-typography-paragraph copyable :copy-text="record.url">
<template #copy-tooltip>复制链接</template> <template #copy-tooltip>复制链接</template>
{{ getFileName(record) }} {{ record.originalName }}
</a-typography-paragraph> </a-typography-paragraph>
</section> </section>
<template #content> <template #content>
@@ -90,11 +90,6 @@ interface Props {
isBatchMode?: boolean isBatchMode?: boolean
} }
// 文件名称带后缀
const getFileName = (item: FileItem) => {
return `${item.name}${item.extension ? `.${item.extension}` : ''}`
}
const rowSelection: TableRowSelection = reactive({ const rowSelection: TableRowSelection = reactive({
type: 'checkbox', type: 'checkbox',
showCheckedAll: true, showCheckedAll: true,

View File

@@ -38,7 +38,7 @@
<icon-delete /> <icon-delete />
</template> </template>
</a-button> </a-button>
<a-button type="primary" :disabled="!queryForm.absPath" @click="createDirModalVisible = !createDirModalVisible"> <a-button type="primary" :disabled="!queryForm.path" @click="createDirModalVisible = !createDirModalVisible">
<template #icon> <template #icon>
<icon-folder /> <icon-folder />
</template> </template>
@@ -105,7 +105,7 @@ import FileGrid from './FileGrid.vue'
import useFileManage from './useFileManage' import useFileManage from './useFileManage'
import { useTable } from '@/hooks' import { useTable } from '@/hooks'
import { type FileItem, type FileQuery, createDir, deleteFile, listFile, uploadFile } from '@/apis' import { type FileItem, type FileQuery, createDir, deleteFile, listFile, uploadFile } from '@/apis'
import { DirTypes, ImageTypes, OfficeTypes } from '@/constant/file' import { ImageTypes, OfficeTypes } from '@/constant/file'
import 'viewerjs/dist/viewer.css' import 'viewerjs/dist/viewer.css'
import { downloadByUrl } from '@/utils/downloadFile' import { downloadByUrl } from '@/utils/downloadFile'
import mittBus from '@/utils/mitt' import mittBus from '@/utils/mitt'
@@ -119,12 +119,12 @@ const { mode, selectedFileIds, toggleMode, addSelectedFileItem } = useFileManage
const queryTypeOption = [{ const queryTypeOption = [{
label: '文件名', label: '文件名',
value: 'name', value: 'originalName',
}, { }, {
label: '路径', label: '路径',
value: 'absPath', value: 'path',
}] }]
const queryType = ref<string>('name') const queryType = ref<string>('originalName')
// 新建文件夹弹窗显示 // 新建文件夹弹窗显示
const createDirModalVisible = ref<boolean>(false) const createDirModalVisible = ref<boolean>(false)
@@ -132,15 +132,15 @@ const createDirModalVisible = ref<boolean>(false)
const newDirName = ref() const newDirName = ref()
const queryForm = reactive<FileQuery>({ const queryForm = reactive<FileQuery>({
name: undefined, originalName: undefined,
absPath: '/', path: (!route.query.type || route.query.type?.toString() === '0') ? '/' : undefined,
type: route.query.type?.toString() !== '0' ? route.query.type?.toString() : undefined, type: route.query.type?.toString() && route.query.type?.toString() !== '0' ? route.query.type?.toString() : undefined,
sort: ['updateTime,desc'], sort: ['type,asc', 'updateTime,desc'],
}) })
const reset = () => { const reset = () => {
queryForm.name = undefined queryForm.originalName = undefined
queryForm.absPath = undefined queryForm.path = undefined
} }
const paginationOption = reactive({ const paginationOption = reactive({
@@ -186,7 +186,7 @@ const handleClickFile = (item: FileItem) => {
}, },
} }
filePreviewRef.value.onPreview({ filePreviewRef.value.onPreview({
fileInfo: { data: item.url, fileName: item.name, fileType: item.extension }, fileInfo: { data: item.url, fileName: item.originalName, fileType: item.extension },
excelConfig, excelConfig,
}) })
} }
@@ -200,12 +200,8 @@ const handleClickFile = (item: FileItem) => {
// 双击文件 // 双击文件
const handleDblclickFile = (item: FileItem) => { const handleDblclickFile = (item: FileItem) => {
if (DirTypes.includes(item.extension)) { if (item.type === 0) {
if (item.absPath.endsWith('/')) { queryForm.path = `${item.path === '/' ? '' : item.path}/${item.name}`
queryForm.absPath = item.absPath + item.name
} else {
queryForm.absPath = `${item.absPath}/${item.name}`
}
search() search()
} }
} }
@@ -215,7 +211,7 @@ const onDownload = async (fileInfo: FileItem) => {
const res = await downloadByUrl({ const res = await downloadByUrl({
url: fileInfo.url, url: fileInfo.url,
target: '_self', target: '_self',
fileName: `${fileInfo.name}.${fileInfo.extension}`, fileName: fileInfo.originalName,
}) })
res ? Message.success('下载成功') : Message.error('下载失败') res ? Message.success('下载成功') : Message.error('下载失败')
search() search()
@@ -226,7 +222,7 @@ const handleRightMenuClick = async (mode: string, fileInfo: FileItem) => {
if (mode === 'delete') { if (mode === 'delete') {
Modal.warning({ Modal.warning({
title: '提示', title: '提示',
content: `是否确定删除文件${fileInfo.name}」?`, content: `是否确定删除${fileInfo.type === 0 ? '文件夹' : '文件'}${fileInfo.originalName}」?`,
hideCancel: false, hideCancel: false,
okButtonProps: { status: 'danger' }, okButtonProps: { status: 'danger' },
onOk: async () => { onOk: async () => {
@@ -273,7 +269,7 @@ const handleUpload = (options: RequestOption) => {
const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options const { onProgress, onError, onSuccess, fileItem, name = 'file' } = options
onProgress(20) onProgress(20)
const formData = new FormData() const formData = new FormData()
formData.append('path', queryForm.absPath ?? '/') formData.append('path', queryForm.path ?? '/')
formData.append(name as string, fileItem.file as Blob) formData.append(name as string, fileItem.file as Blob)
try { try {
const res = await uploadFile(formData) const res = await uploadFile(formData)
@@ -295,10 +291,12 @@ const handleUpload = (options: RequestOption) => {
onBeforeRouteUpdate((to) => { onBeforeRouteUpdate((to) => {
if (!to.query.type) return if (!to.query.type) return
if (to.query.type === '0') { if (to.query.type === '0' || !to.query.type) {
queryForm.type = undefined queryForm.type = undefined
queryForm.path = '/'
} else { } else {
queryForm.type = to.query.type?.toString() queryForm.type = to.query.type?.toString()
queryForm.path = undefined
} }
search() search()
@@ -312,7 +310,7 @@ const handleCancel = () => {
// 新建文件夹弹窗窗口确认事件 // 新建文件夹弹窗窗口确认事件
const handleCreateDir = async () => { const handleCreateDir = async () => {
await createDir(queryForm.absPath ?? '/', newDirName.value) await createDir(queryForm.path ?? '/', newDirName.value)
newDirName.value = undefined newDirName.value = undefined
createDirModalVisible.value = false createDirModalVisible.value = false
search() search()