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