完成イメージ
画像をアップロードして...
こんな感じに画像がアップロードされる。
DELETEボタンを押すとメッセージが表示されて....
画面から画像が削除される。
uploadthingのダッシュボードにからも削除される
以上のサンプルを作っていきます。
ディレクトリ構造
.
└── NuxtDjangoProject/
├── backend/
│ ├── adminuser
│ ├── api/
│ │ ├── migrations/
│ │ │ └── 0001_initial.py
│ │ ├── serializer.py
│ │ ├── urls.py
│ │ └── views.py
│ └── todoproject/
│ ├── settings.py
│ └── urls.py
└── frontend/
├── components/
│ ├── footer/
│ │ └── footer.vue
│ └── navbar/
│ └── navbar.vue
├── pages/
│ ├── adminUsers/
│ │ ├── login/
│ │ │ └── login.vue
│ │ ├── registration/
│ │ │ └── registration.vue
│ │ ├── updateProfile/
│ │ │ └── updateProfile.vue
│ │ └── uploadImageFile/
│ │ └── uploadImageFile.vue
│ ├── login/
│ │ └── login.vue
│ ├── registration/
│ │ └── registration.vue
│ └── index.vue
├── .env
├── server/
│ ├── api/
│ │ └── uploadthing/
│ │ └── delete.ts
│ └── uploadthing.ts
├── app.vue
├── nuxtconfig.ts/
│ └── package.json
└── tsxconfig.json
サーバ側の処理
サーバ側の処理は下記のとおりです。
frontend/server/api/uploadthing/delete.ts
import { UTApi } from "uploadthing/server";
import { z } from 'zod'
const utapi = new UTApi({
apiKey:process.env.UPLOADTHING_TOKEN
});
export default defineEventHandler(async (event)=>{
try{
const body = await readBody(event);
const { key } = z.object({key:z.string()}).parse(body);
if(!process.env.UPLOADTHING_TOKEN){
console.log('Please set UPLOADTHING_TOKEN.');
throw new Error('UPLOADTHING_SECRET is not set.');
}
const response = await utapi.deleteFiles([key]);
console.log('Uploadthing delete response:',response);
if(response.success){
return {success:true};
}else{
console.log('Uploadthing delete failed:',response.error);
return {success:false,error:response.error};
}
}catch(error:any){
console.error('サーバーエラー:', error);
return { success: false, error: error.message };
}
});
フロント側の処理
フロント側の処理は下記のとおりです。
frontend/pages/adminUsers/uploadImageFile/uploadImageFile.vue
<script setup lang="ts">
import { useRouter } from 'vue-router';
import { ref } from 'vue'
import { useFetch } from 'nuxt/app'
const router = useRouter();
const alert = (msg: string) => {
window.alert(msg);
};
/** Method for deleting image */
const fileRef = ref<File | null>(null);// Type is set at File or null
const imageKey = ref<string>('');
const setImageInfo = (data:any)=>{
imageKey.value = file[0].key;
}
const clickImageDelete = async()=>{
if(!imageKey.value){
alert('Please select targe image.');
return;
}
const { data,error } = await useFetch('/api/uploadthing/delete',{
method:'POST',
body:{
key:imageKey.value,
},
});
if(error.value){
console.log('Fail delete image,',error.value);
alert('Faile delete image.');
return;
}
if(data.value?.success){
alert('Success to delete target image.');
fileRef.value = null;
imageKey.value = '';
}else{
alert('Fail to delete.');
}
}
</script>
<template>
<div>
<UploadButton
:config="{
endpoint: 'imageUploader',
onClientUploadComplete: (file) => {
if(file && file.length > 0){
console.log('file:', file[0]);//Debug file object.
console.log('file[0].key:', file[0].key); // Debug file[0].key.
console.log('Convert String type for file[0].key is :', String(file[0].key)); // Convert type of string.
fileRef = file[0].url;// Debug file[0].url.
imageKey = String(file[0].key);
console.log('imageKey.key:', imageKey); // 追加
console.log('fileRef after upload:', fileRef); // 追加
}
alert('Upload complete');
},
onUploadError: (error) => {
console.error(error, error.cause);
alert('Upload failed');
},
}"
/>
<UploadDropzone
:config="{
endpoint: 'imageUploader',
onClientUploadComplete: (file) => {
console.log('uploaded', file);
console.log('uploaded', file[0].url);
console.log('uploaded', file[0].key);
fileRef = file[0].url;// Debug file[0].url.
imageKey = String(file[0].key);
alert('Upload complete');
},
onUploadError: (error) => {
console.error(error, error.cause);
alert('Upload failed');
},
}"
/>
<!-- Image thumbnail Area -->
<div v-if="imageKey" class="flex items-center justify-center">
<v-avatar size="x-large">
<v-img
:src="fileRef"
></v-img>
</v-avatar>
</div>
<!-- Image key Area -->
<div>
<input type="hidden" :value="imageKey"/>
</div>
<!-- Image thumbnail button Area -->
<div v-if="imageKey" class="flex items-center justify-center mt-8">
<v-btn
type="button"
color="success"
@click="clickImageDelete"
>
Delete
</v-btn>
</div>
</div>
</template>
以上です。