Ant Design Vue の <a-upload> コンポーネントを拡張し、ファイルのアップロード・ダウンロード・削除機能を実装する方法を紹介します。API の download イベントが期待通りに動作しなかったため、代わりに preview イベントを活用してダウンロード処理を実現しています。
親コンポーネントからの呼び出し例
<new-upload
ref="upDataMout"
:upload-action-url="url.uploadAction"
:url-download="url.urlDownload"
:delete-url="url.deleteUrl"
@upload-file="uploadFile"
/>
カスタムアップロードコンポーネントの実装
<template>
<a-upload
name="file"
:multiple="true"
:disabled="isDisabled"
:file-list="uploadedFiles"
@change="onFileChange"
@preview="triggerDownload"
:remove="onFileRemove"
:before-upload="onBeforeUpload"
:show-upload-list="{
showDownloadIcon: true,
showRemoveIcon: true
}"
>
<a-button size="small">
<a-icon type="upload" style="font-size: 12px;" />{{ buttonText }}
</a-button>
</a-upload>
</template>
<script>
import axios from 'axios';
import { postAction } from '@/api/analysis.js';
const SUPPORTED_FILE_TYPE = 'all';
export default {
name: 'CustomFileUploader',
data() {
return {
uploadedFiles: [],
filePaths: [],
fileNames: [],
isUploading: false,
};
},
props: {
buttonText: {
type: String,
default: 'クリックしてアップロード'
},
fileType: {
type: String,
default: SUPPORTED_FILE_TYPE
},
value: {
type: [String, Array],
default: null
},
isDisabled: {
type: Boolean,
default: false
},
uploadActionUrl: {
type: String,
default: ''
},
urlDownload: {
type: String,
default: ''
},
deleteUrl: {
type: String,
default: ''
}
},
methods: {
generateUid() {
return '-' + Math.floor(Math.random() * 10000 + 1);
},
clearPreviousFiles() {
this.$nextTick(() => {
this.uploadedFiles = [];
this.filePaths = [];
this.fileNames = [];
});
},
loadExistingFiles(record) {
const fileNameList = record.fileName ? record.fileName.split(',') : [];
const folderPath = record.folderId || '';
const fileList = fileNameList.map(name => ({
uid: this.generateUid(),
name,
status: 'done',
url: folderPath,
response: {
status: 'history',
message: folderPath
}
}));
this.$nextTick(() => {
this.uploadedFiles = fileList;
this.filePaths = Array(fileNameList.length).fill(folderPath);
this.fileNames = fileNameList;
});
},
async onFileRemove(file) {
try {
await this.$confirm('このファイルを削除しますか?', { type: 'error' });
const index = this.uploadedFiles.indexOf(file);
const newFileList = [...this.uploadedFiles];
newFileList.splice(index, 1);
this.uploadedFiles = newFileList;
const fileName = file.name;
const filePath = this.filePaths[index];
const updatedPaths = [...this.filePaths];
updatedPaths.splice(index, 1);
this.filePaths = updatedPaths;
const updatedNames = [...this.fileNames];
updatedNames.splice(index, 1);
this.fileNames = updatedNames;
const deleteUrl = `${this.deleteUrl}?fileName=${encodeURIComponent(fileName)}&filedir=${encodeURIComponent(filePath)}`;
const res = await postAction(deleteUrl);
if (res.status === 1) {
this.$emit('upload-file', {
fileName: this.fileNames,
filedir: this.filePaths[0] || ''
});
this.$message.success('ファイルを削除しました');
}
} catch (err) {
console.log('削除がキャンセルされました');
}
},
onBeforeUpload(file) {
this.uploadedFiles = [...this.uploadedFiles, file];
return false;
},
async onFileChange(info) {
if (info.file.status === 'removed') return;
const formData = new FormData();
this.uploadedFiles.forEach(f => {
formData.append('files', f);
});
this.isUploading = true;
try {
const response = await axios.post(this.uploadActionUrl, formData, {
headers: { 'Content-Type': 'multipart/form-data' }
});
if (response.status === 200) {
const { data } = response;
const newFilePath = data.filedir;
const newFileName = info.file.name;
this.fileNames.push(newFileName);
this.filePaths.push(newFilePath);
const lastIndex = this.uploadedFiles.length - 1;
this.uploadedFiles[lastIndex].url = newFilePath;
this.uploadedFiles[lastIndex].status = 'done';
this.$message.success(`${data.fileName} のアップロードが完了しました`);
this.$emit('upload-file', {
fileName: this.fileNames,
filedir: this.filePaths[0]
});
}
} catch (error) {
console.error('アップロードエラー:', error);
this.$message.error('ファイルのアップロードに失敗しました');
} finally {
this.isUploading = false;
}
},
triggerDownload(file) {
const index = this.uploadedFiles.indexOf(file);
const filePath = this.filePaths[index];
const downloadUrl = `${this.urlDownload}?fileName=${encodeURIComponent(file.name)}&filedir=${encodeURIComponent(filePath)}`;
window.open(downloadUrl, '_blank');
}
},
model: {
prop: 'value',
event: 'change'
}
};
</script>