From 5123b3e95b820cd3fbe36648db0781008250ae25 Mon Sep 17 00:00:00 2001 From: Lan Date: Wed, 7 Jan 2026 18:54:41 +0800 Subject: [PATCH] fix: https://github.com/vastsa/FileCodeBox/issues/322 --- src/i18n/locales/en-US.ts | 79 ++++++++++++------------- src/i18n/locales/zh-CN.ts | 53 ++++++++--------- src/views/SendFileView.vue | 117 ++++++++++++++++++++++++------------- vite.config.ts | 3 +- 4 files changed, 143 insertions(+), 109 deletions(-) diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 550b53e..e5ff285 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -189,6 +189,7 @@ export default { description: 'Supports various common formats' }, submit: 'Secure Send', + submitting: 'Sending...', needRetrieveFile: 'Need to retrieve? Click here', sendRecords: 'Send Records', secureEncryption: 'Secure Encryption', @@ -217,7 +218,7 @@ export default { forever: 'Forever' } }, - time: { + time: { day: 'By Day', hour: 'By Hour', minute: 'By Minute', @@ -311,7 +312,7 @@ export default { } }, - // Side drawer + // Side drawer drawer: { noRecords: 'No records' }, @@ -466,42 +467,42 @@ export default { version: 'Version v2.2.1 Updated: 2025-09-04' }, fileManage: { - title: 'File Management', - searchPlaceholder: 'Search file name, description...', - allFiles: 'All Files', - editFileInfo: 'Edit File Info', - saveChanges: 'Save Changes', - headers: { - code: 'Code', - name: 'Name', - size: 'Size', - description: 'Description', - expiration: 'Expiration', - actions: 'Actions' - }, - form: { - code: 'Code', - codePlaceholder: 'Enter code', - filename: 'File Name', - filenamePlaceholder: 'Enter file name', - suffix: 'File Suffix', - suffixPlaceholder: 'Enter file suffix', - downloadLimit: 'Download Limit', - downloadLimitPlaceholder: 'Enter download limit' - }, - updateFailed: 'Update failed', - deleteFailed: 'Delete failed', - loadFileListFailed: 'Failed to load file list' - }, - login: { - title: 'Login', - password: 'Password', - passwordPlaceholder: 'Password', - loginButton: 'Login', - loggingIn: 'Logging in...', - invalidPassword: 'Invalid password', - passwordTooShort: 'Password must be at least 6 characters', - loginFailed: 'Login failed', + title: 'File Management', + searchPlaceholder: 'Search file name, description...', + allFiles: 'All Files', + editFileInfo: 'Edit File Info', + saveChanges: 'Save Changes', + headers: { + code: 'Code', + name: 'Name', + size: 'Size', + description: 'Description', + expiration: 'Expiration', + actions: 'Actions' + }, + form: { + code: 'Code', + codePlaceholder: 'Enter code', + filename: 'File Name', + filenamePlaceholder: 'Enter file name', + suffix: 'File Suffix', + suffixPlaceholder: 'Enter file suffix', + downloadLimit: 'Download Limit', + downloadLimitPlaceholder: 'Enter download limit' + }, + updateFailed: 'Update failed', + deleteFailed: 'Delete failed', + loadFileListFailed: 'Failed to load file list' + }, + login: { + title: 'Login', + password: 'Password', + passwordPlaceholder: 'Password', + loginButton: 'Login', + loggingIn: 'Logging in...', + invalidPassword: 'Invalid password', + passwordTooShort: 'Password must be at least 6 characters', + loginFailed: 'Login failed', noValidToken: 'Login failed: No valid token received' } }, @@ -600,4 +601,4 @@ export default { delayedLoading: 'Use onMounted hook to delay load non-critical resources or initialization', nonCriticalInit: 'Place non-immediately needed initialization code here' } -} \ No newline at end of file +} diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index 1596dda..157aecd 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -190,6 +190,7 @@ export default { description: '支持各种常见格式' }, submit: '安全寄送', + submitting: '发送中...', needRetrieveFile: '需要取件?点击这里', sendRecords: '发件记录', secureEncryption: '安全加密', @@ -311,35 +312,35 @@ export default { }, // 文件记录 - fileRecord: { - filename: '文件名', - size: '文件大小', - date: '取件日期', - code: '取件码', - actions: '操作', - download: '下载', - viewDetails: '查看详情', - deleteRecord: '删除记录', - preview: '预览', - copyContent: '复制内容', - contentCopied: '内容已复制到剪贴板', - copyFailed: '复制失败,请重试' - }, + fileRecord: { + filename: '文件名', + size: '文件大小', + date: '取件日期', + code: '取件码', + actions: '操作', + download: '下载', + viewDetails: '查看详情', + deleteRecord: '删除记录', + preview: '预览', + copyContent: '复制内容', + contentCopied: '内容已复制到剪贴板', + copyFailed: '复制失败,请重试' + }, // 文件详情模态框 fileDetail: { - title: '文件详情', - content: '文件内容', - previewContent: '预览内容', - download: '点击下载', - qrCode: '取件二维码', - scanQrCode: '扫描二维码快速取件' - }, + title: '文件详情', + content: '文件内容', + previewContent: '预览内容', + download: '点击下载', + qrCode: '取件二维码', + scanQrCode: '扫描二维码快速取件' + }, - // 内容预览 - contentPreview: { - title: '内容预览' - }, + // 内容预览 + contentPreview: { + title: '内容预览' + }, // 侧边抽屉 drawer: { @@ -622,4 +623,4 @@ export default { delayedLoading: '使用 onMounted 钩子延迟加载一些非关键资源或初始化', nonCriticalInit: '这里可以放置一些非立即需要的初始化代码' } -} \ No newline at end of file +} diff --git a/src/views/SendFileView.vue b/src/views/SendFileView.vue index 1f08d87..dcc9387 100644 --- a/src/views/SendFileView.vue +++ b/src/views/SendFileView.vue @@ -30,10 +30,7 @@ />
- +
@@ -115,7 +112,9 @@ :class="[ 'absolute right-0 top-0 h-full appearance-none cursor-pointer transition-all duration-300', 'focus:outline-none focus:ring-2 focus:ring-offset-0', - expirationMethod === 'forever' ? 'w-full px-5 rounded-2xl' : 'w-28 pl-4 pr-9 border-l rounded-r-2xl', + expirationMethod === 'forever' + ? 'w-full px-5 rounded-2xl' + : 'w-28 pl-4 pr-9 border-l rounded-r-2xl', isDarkMode ? 'text-gray-100 border-gray-700/60 focus:ring-indigo-500/80 bg-gray-800/60' : 'text-gray-900 border-gray-200 focus:ring-indigo-500/60 bg-white' @@ -166,14 +165,36 @@ @@ -532,8 +553,6 @@ interface ShareRecord { retrieveCode: string } - - const config: Config = JSON.parse(localStorage.getItem('config') || '{}') as Config const router = useRouter() @@ -549,6 +568,7 @@ const expirationValue = ref('1') const uploadProgress = ref(0) const showDrawer = ref(false) const selectedRecord = ref(null) +const isSubmitting = ref(false) const { t } = useI18n() const alertStore = useAlertStore() @@ -564,8 +584,6 @@ const { const fileHash = ref('') - - const handleFileSelected = async (file: File) => { selectedFile.value = file if (!checkOpenUpload()) return @@ -573,8 +591,6 @@ const handleFileSelected = async (file: File) => { fileHash.value = await calculateFileHash(file) } - - const handleFileDrop = async (event: DragEvent) => { if (event.dataTransfer?.files && event.dataTransfer.files.length > 0) { const file = event.dataTransfer.files[0] @@ -604,7 +620,10 @@ const handlePaste = async (event: ClipboardEvent) => { try { fileHash.value = await calculateFileHash(file) - alertStore.showAlert(t('send.messages.fileAddedFromClipboard', { filename: file.name }), 'success') + alertStore.showAlert( + t('send.messages.fileAddedFromClipboard', { filename: file.name }), + 'success' + ) } catch (err) { alertStore.showAlert(t('send.messages.fileProcessingFailed'), 'error') console.error('File hash calculation failed:', err) @@ -860,10 +879,13 @@ const handleChunkUpload = async (file: File) => { } // 3. 完成上传 - const completeResponse: ApiResponse<{ code?: string; name?: string }> = await api.post(`chunk/upload/complete/${uploadId}`, { - expire_value: expirationValue.value ? parseInt(expirationValue.value) : 1, - expire_style: expirationMethod.value - }) + const completeResponse: ApiResponse<{ code?: string; name?: string }> = await api.post( + `chunk/upload/complete/${uploadId}`, + { + expire_value: expirationValue.value ? parseInt(expirationValue.value) : 1, + expire_style: expirationMethod.value + } + ) if (completeResponse.code !== 200) { throw new Error(t('send.messages.completeUploadFailed')) @@ -898,7 +920,11 @@ const handleDefaultFileUpload = async (file: File) => { formData.append('file', file) formData.append('expire_value', expirationValue.value) formData.append('expire_style', expirationMethod.value) - const response: ApiResponse<{ code?: string; name?: string }> = await api.post('share/file/', formData, config) + const response: ApiResponse<{ code?: string; name?: string }> = await api.post( + 'share/file/', + formData, + config + ) return response } @@ -933,7 +959,10 @@ const checkOpenUpload = () => { const checkFileSize = (file: File) => { if (file.size > config.uploadSize) { - alertStore.showAlert(t('send.messages.fileSizeExceeded', { size: getStorageUnit(config.uploadSize) }), 'error') + alertStore.showAlert( + t('send.messages.fileSizeExceeded', { size: getStorageUnit(config.uploadSize) }), + 'error' + ) selectedFile.value = null return false } @@ -971,27 +1000,30 @@ const checkUpload = () => { return true } const handleSubmit = async () => { - if (sendType.value === 'file' && !selectedFile.value) { - alertStore.showAlert(t('send.messages.selectFile'), 'error') - return - } - if (sendType.value === 'text' && !textContent.value.trim()) { - alertStore.showAlert(t('send.messages.enterText'), 'error') - return - } - if (expirationMethod.value !== 'forever' && !expirationValue.value) { - alertStore.showAlert(t('send.messages.enterExpirationValue'), 'error') - return - } - - // 添加过期时间验证 - if (!checkExpirationTime(expirationMethod.value, expirationValue.value)) { - const maxDays = Math.floor(config.max_save_seconds / 86400) - alertStore.showAlert(t('send.messages.expirationTooLong', { days: maxDays }), 'error') - return - } + if (isSubmitting.value) return + isSubmitting.value = true try { + if (sendType.value === 'file' && !selectedFile.value) { + alertStore.showAlert(t('send.messages.selectFile'), 'error') + return + } + if (sendType.value === 'text' && !textContent.value.trim()) { + alertStore.showAlert(t('send.messages.enterText'), 'error') + return + } + if (expirationMethod.value !== 'forever' && !expirationValue.value) { + alertStore.showAlert(t('send.messages.enterExpirationValue'), 'error') + return + } + + // 添加过期时间验证 + if (!checkExpirationTime(expirationMethod.value, expirationValue.value)) { + const maxDays = Math.floor(config.max_save_seconds / 86400) + alertStore.showAlert(t('send.messages.expirationTooLong', { days: maxDays }), 'error') + return + } + let response: ApiResponse if (sendType.value === 'file') { @@ -1020,8 +1052,8 @@ const handleSubmit = async () => { } if (response && response.code === 200) { - const retrieveCode = (response.detail as unknown as { code?: string })?.code || '' - const fileName = (response.detail as unknown as { name?: string })?.name || '' + const retrieveCode = (response.detail as unknown as { code?: string })?.code || '' + const fileName = (response.detail as unknown as { name?: string })?.name || '' // 添加新的发送记录 const newRecord: ShareRecord = { id: Date.now(), @@ -1064,6 +1096,7 @@ const handleSubmit = async () => { } } finally { uploadProgress.value = 0 + isSubmitting.value = false } } diff --git a/vite.config.ts b/vite.config.ts index d3d07e7..058b471 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,11 +3,10 @@ import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vueJsx from '@vitejs/plugin-vue-jsx' -import vueDevTools from 'vite-plugin-vue-devtools' import tailwindcss from 'tailwindcss' import autoprefixer from 'autoprefixer' export default defineConfig({ - plugins: [vue(), vueJsx(), vueDevTools()], + plugins: [vue(), vueJsx()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url))