| <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> |
|
|