|
<script setup lang="ts"> |
|
import { ref, watch } from 'vue'; |
|
import { useRoute, useRouter } from 'vue-router'; |
|
import { MessagePlugin, type UploadFile, type UploadInstanceFunctions, type UploadProps } from 'tdesign-vue-next'; |
|
import { UploadIcon } from 'tdesign-icons-vue-next'; |
|
import { useAccountStore } from '../stores/accountStorage'; |
|
import { repoApi } from '../services/repoApi'; |
|
import RepoHeader from '../components/RepoHeader.vue'; |
|
|
|
const route = useRoute(); |
|
const router = useRouter(); |
|
const store = useAccountStore(); |
|
|
|
const selectedAccount = ref<number | ''>(''); |
|
const currentPath = ref(''); |
|
const loading = ref(false); |
|
const uploadRef = ref<UploadInstanceFunctions>(); |
|
const uploadFiles = ref<UploadProps['value']>([]); |
|
const commitMessage = ref(''); |
|
const commitDescription = ref(''); |
|
const selectedFile = ref<File | null>(null); |
|
|
|
|
|
watch(() => route.query, async (query) => { |
|
if (route.path !== '/upload') return; |
|
const { id, path } = query; |
|
if (id) { |
|
await store.fetchAccounts(); |
|
const account = store.accounts.find(acc => acc.id === Number(id)); |
|
if (account) { |
|
selectedAccount.value = account.id; |
|
} |
|
currentPath.value = path ? path as string : ''; |
|
} |
|
uploadFiles.value = []; |
|
}, { immediate: true }); |
|
|
|
const handlePathClick = (path: string) => { |
|
router.push({ |
|
path: '/repo', |
|
query: { |
|
id: selectedAccount.value, |
|
path |
|
} |
|
}); |
|
}; |
|
|
|
const handleRootClick = () => { |
|
router.push({ |
|
path: '/repo', |
|
query: { |
|
id: selectedAccount.value, |
|
} |
|
}); |
|
}; |
|
|
|
const handleAccountChange = (val: number) => { |
|
selectedAccount.value = val; |
|
currentPath.value = ''; |
|
router.push({ |
|
path: '/repo', |
|
query: { |
|
id: selectedAccount.value, |
|
} |
|
}); |
|
}; |
|
|
|
const handleUpload = async (files: UploadFile[]) => { |
|
if (!selectedAccount.value) { |
|
MessagePlugin.error('请先选择仓库'); |
|
return; |
|
} |
|
|
|
if (!files || files.length === 0) { |
|
MessagePlugin.error('请选择要上传的文件'); |
|
return; |
|
} |
|
selectedFile.value = files[0].raw as File; |
|
}; |
|
|
|
const handleConfirmUpload = async () => { |
|
if (!selectedFile.value || !selectedAccount.value) return; |
|
|
|
const account = store.accounts.find(acc => acc.id === selectedAccount.value); |
|
if (!account) { |
|
MessagePlugin.error('未找到账户信息'); |
|
return; |
|
} |
|
|
|
loading.value = true; |
|
try { |
|
|
|
if (!(selectedFile.value instanceof File)) { |
|
throw new Error('Invalid file object'); |
|
} |
|
|
|
const content = await new Promise<Uint8Array>((resolve, reject) => { |
|
const reader = new FileReader(); |
|
reader.onload = (e) => { |
|
if (e.target?.result) { |
|
resolve(e.target.result as Uint8Array); |
|
} else { |
|
reject(new Error('Failed to read file content')); |
|
} |
|
}; |
|
reader.onerror = () => reject(reader.error); |
|
|
|
reader.readAsArrayBuffer(selectedFile.value as File); |
|
}); |
|
|
|
const filePath = currentPath.value |
|
? `${currentPath.value}/${selectedFile.value.name}` |
|
: selectedFile.value.name; |
|
|
|
const finalCommitMessage = commitMessage.value.trim() + |
|
(commitDescription.value ? '\n\n' + commitDescription.value.trim() : '') || |
|
`上传文件: ${selectedFile.value.name}`; |
|
|
|
|
|
const response = await repoApi.createAsset( |
|
account, |
|
filePath, |
|
content, |
|
finalCommitMessage |
|
); |
|
|
|
MessagePlugin.success('上传成功'); |
|
|
|
commitMessage.value = ''; |
|
commitDescription.value = ''; |
|
selectedFile.value = null; |
|
|
|
router.push({ |
|
path: '/repo', |
|
query: { |
|
id: selectedAccount.value, |
|
path: currentPath.value |
|
} |
|
}); |
|
} catch (error) { |
|
console.error(error); |
|
MessagePlugin.error('上传失败'); |
|
} finally { |
|
loading.value = false; |
|
} |
|
}; |
|
|
|
const handleCancelUpload = () => { |
|
commitMessage.value = ''; |
|
commitDescription.value = ''; |
|
selectedFile.value = null; |
|
}; |
|
</script> |
|
|
|
<template> |
|
<div class="upload-container w-full flex flex-col p-3 md:p-5 gap-3 md:gap-5 bg-gray-50"> |
|
<RepoHeader :selected-account="selectedAccount" :current-path="currentPath" :accounts="store.accounts" |
|
:is-upload-file="true" @path-click="handlePathClick" @root-click="handleRootClick" |
|
@update:selected-account="handleAccountChange" /> |
|
|
|
<div class="content-section flex-1 bg-white rounded-lg shadow-sm p-6"> |
|
<t-upload ref="uploadRef" v-model="uploadFiles" class="w-full flex items-center justify-center" theme="image" :auto-upload="false" |
|
:multiple="false" :draggable="true" :allow-upload-duplicate-file="true" @change="handleUpload"> |
|
</t-upload> |
|
|
|
|
|
<div class="mt-6 pt-4"> |
|
<div class="flex flex-col gap-4"> |
|
<t-input v-model:value="commitMessage" placeholder="请输入提交标题" :autofocus="true" /> |
|
<t-textarea v-model:value="commitDescription" placeholder="请输入详细的提交说明(可选)" |
|
class="commit-description-textarea" /> |
|
<div class="flex gap-2 justify-end"> |
|
<t-button theme="default" @click="handleCancelUpload"> |
|
取消 |
|
</t-button> |
|
<t-button theme="primary" @click="handleConfirmUpload" :loading="loading"> |
|
确认上传 |
|
</t-button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
</template> |
|
|
|
<style scoped> |
|
.upload-container { |
|
min-height: 600px; |
|
} |
|
:deep(.t-upload__dragger){ |
|
@apply w-full; |
|
} |
|
</style> |
|
|