diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index f7140da..414fba8 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -1386,5 +1386,10 @@ "请选择一个原因": "请选择一个原因", "请评价您的体验": "请评价您的体验", "请简要说明原因": "请简要说明原因", - "Your feedback has been submitted successfully": "您的反馈已成功提交" + "Your feedback has been submitted successfully": "您的反馈已成功提交", + "Portrait Sample": "人物示例", + "Product Sample": "产品示例", + "Animal Sample": "动物示例", + "Object Sample": "物品示例", + "Unable to get team information": "无法获取团队信息" } diff --git a/src/views/HomePage.vue b/src/views/HomePage.vue index 2ca419e..8d735c7 100644 --- a/src/views/HomePage.vue +++ b/src/views/HomePage.vue @@ -17,7 +17,7 @@ const appName = computed(() => localStorage.getItem('appName') || 'Jingrow') const currentYear = computed(() => new Date().getFullYear()) const logoUrl = computed(() => '/logo.svg') -// 登录/注册弹窗状态 +// Login/Signup modal state const showLoginModal = ref(false) const showSignupModal = ref(false) const loginFormRef = ref() @@ -26,7 +26,7 @@ const loginLoading = ref(false) const signupLoading = ref(false) const showSignupLink = ref(true) -// 登录表单 +// Login form const loginFormData = reactive({ username: '', password: '' @@ -42,7 +42,7 @@ const loginRules = { ] } -// 注册表单 +// Signup form const signupFormData = reactive({ username: '', password: '', @@ -76,13 +76,13 @@ const signupRules = computed(() => { ] } - // 英文版:email必填,手机号可选 + // English version: email required, phone optional if (isEnglish.value) { rules.email = [ { required: true, message: t('Please enter email'), trigger: 'blur' }, { validator: (_rule: any, value: string) => { - // required规则已处理空值,这里只验证格式 + // Required rule handles empty values, only validate format here if (!value) return true const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ if (!emailRegex.test(value)) { @@ -107,7 +107,7 @@ const signupRules = computed(() => { } ] } else { - // 中文版:email可选,手机号必填 + // Chinese version: email optional, phone required rules.email = [ { validator: (_rule: any, value: string) => { @@ -205,11 +205,9 @@ const handleSignupSubmit = async () => { } } else { const errorMsg = result.error || t('Sign up failed') - console.error('注册失败:', errorMsg, result) message.error(errorMsg) } } catch (error: any) { - console.error('注册异常:', error) message.error(error.message || t('Sign up failed, please try again')) } finally { signupLoading.value = false @@ -226,15 +224,15 @@ const switchToLogin = () => { showLoginModal.value = true } -// 登录状态 +// Login state const isLoggedIn = computed(() => authStore.isLoggedIn) -// Sidebar 折叠状态 +// Sidebar collapse state const SIDEBAR_COLLAPSE_KEY = 'app.sidebar.collapsed' const collapsed = ref(localStorage.getItem(SIDEBAR_COLLAPSE_KEY) === 'true') const isMobile = ref(false) -// 检测屏幕尺寸 +// Check screen size const checkIsMobile = () => { isMobile.value = window.innerWidth < 768 if (isMobile.value) { @@ -242,29 +240,29 @@ const checkIsMobile = () => { } } -// 切换侧边栏 +// Toggle sidebar const toggleSidebar = () => { collapsed.value = !collapsed.value } -// 侧边栏折叠事件 +// Sidebar collapse event const onSidebarCollapse = () => { collapsed.value = true } -// 侧边栏展开事件 +// Sidebar expand event const onSidebarExpand = () => { collapsed.value = false } -// 菜单选择事件 - 移动端自动关闭 +// Menu select event - auto close on mobile const onMenuSelect = () => { if (isMobile.value) { collapsed.value = true } } -// 监听窗口大小变化 +// Handle window resize const handleWindowResize = () => { checkIsMobile() adjustContainerSize() @@ -289,13 +287,13 @@ interface HistoryItem { } const fileInputRef = ref(null) -// urlInputRef 在模板中使用,lint 警告是误报 +// urlInputRef is used in template, lint warning is false positive // eslint-disable-next-line @typescript-eslint/no-unused-vars const urlInputRef = ref(null) const uploadedImage = ref(null) const uploadedImageUrl = ref('') const resultImage = ref('') -const resultImageBlobUrl = ref('') // 缓存的 blob URL,用于下载 +const resultImageBlobUrl = ref('') // Cached blob URL for download const imageUrl = ref('') const resultImageUrl = computed(() => { if (!resultImage.value) return '' @@ -309,57 +307,57 @@ const dragCounter = ref(0) const processing = ref(false) const splitPosition = ref(0) -// 示例图片用于快速体验 - 使用适合抠图的图片 +// Sample images for quick experience - suitable for background removal const sampleImages = [ { id: 'sample-1', url: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') }, { id: 'sample-2', url: 'https://images.unsplash.com/photo-1529626455594-4ff0802cfb7e?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') }, { id: 'sample-3', url: 'https://images.unsplash.com/photo-1571019613454-1cb2f99b2d8b?w=1024&h=1024&fit=crop&q=80', - name: '产品示例' + name: t('Product Sample') }, { id: 'sample-4', url: 'https://images.unsplash.com/photo-1523275335684-37898b6baf30?w=1024&h=1024&fit=crop&q=80', - name: '产品示例' + name: t('Product Sample') }, { id: 'sample-5', url: 'https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1024&h=1024&fit=crop&q=80', - name: '动物示例' + name: t('Animal Sample') }, { id: 'sample-6', url: 'https://images.unsplash.com/photo-1551963831-b3b1ca40c98e?w=1024&h=1024&fit=crop&q=80', - name: '物品示例' + name: t('Object Sample') }, { id: 'sample-7', url: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') }, { id: 'sample-8', url: 'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') }, { id: 'sample-9', url: 'https://images.unsplash.com/photo-1517841905240-472988babdf9?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') }, { id: 'sample-10', url: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=1024&h=1024&fit=crop&q=80', - name: '人物示例' + name: t('Portrait Sample') } ] const comparisonContainerRef = ref(null) @@ -453,12 +451,11 @@ const processFile = async (file: File) => { } reader.readAsDataURL(compressedFile) } catch (error) { - console.error('图片压缩失败:', error) - message.error(t('Image processing failed, please try again')) + message.error(t('Image processing failed, please try again')) } } -// 处理示例图片点击 +// Handle sample image click const handleSampleImageClick = async (imageUrl: string) => { if (processing.value) return @@ -472,7 +469,7 @@ const handleSampleImageClick = async (imageUrl: string) => { const blob = await response.blob() - // 验证文件类型 + // Validate file type const validTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/webp'] if (!validTypes.includes(blob.type)) { message.warning(t('Unsupported image format. Please use JPG, PNG, or WebP')) @@ -480,7 +477,7 @@ const handleSampleImageClick = async (imageUrl: string) => { return } - // 验证文件大小 + // Validate file size const maxSize = 10 * 1024 * 1024 if (blob.size > maxSize) { message.warning(t('Image size exceeds 10MB limit')) @@ -488,11 +485,10 @@ const handleSampleImageClick = async (imageUrl: string) => { return } - // 转换为File对象 + // Convert to File object const file = new File([blob], 'sample-image.jpg', { type: blob.type }) await processFile(file) } catch (error: any) { - console.error('加载示例图片失败:', error) let errorMessage = t('Failed to load sample image') if (error.message?.includes('CORS')) { @@ -515,7 +511,7 @@ const handleRemoveBackground = async () => { processing.value = true resultImage.value = '' - // 处理成功结果的辅助函数(文件内部使用) + // Helper function to handle successful result (internal use) const handleSuccess = async (imageUrl: string): Promise => { resultImage.value = imageUrl await cacheResultImage(imageUrl) @@ -581,13 +577,13 @@ const handleRemoveBackground = async () => { message.error(result.error) } } catch (parseError) { - console.error('Failed to parse JSON:', parseError, 'Line:', line) + // Failed to parse JSON, continue processing } } } } - // 处理最后一行 + // Process last line if (buffer.trim()) { try { const result = JSON.parse(buffer.trim()) @@ -598,7 +594,6 @@ const handleRemoveBackground = async () => { message.error(result.error || t('Failed to remove background')) } } catch (parseError) { - console.error('Failed to parse final JSON:', parseError) message.error(t('Failed to parse response')) } } else { @@ -620,17 +615,17 @@ const handleRemoveBackground = async () => { } /** - * 缓存结果图片为 blob URL,用于下载 + * Cache result image as blob URL for download */ const cacheResultImage = async (imageUrl: string) => { try { - // 清理旧的 blob URL + // Clean up old blob URL if (resultImageBlobUrl.value) { URL.revokeObjectURL(resultImageBlobUrl.value) resultImageBlobUrl.value = '' } - // 获取图片并转换为 blob URL + // Fetch image and convert to blob URL const response = await fetch(imageUrl) if (!response.ok) { throw new Error(`Failed to fetch image: ${response.status}`) @@ -638,15 +633,14 @@ const cacheResultImage = async (imageUrl: string) => { const blob = await response.blob() resultImageBlobUrl.value = URL.createObjectURL(blob) } catch (error) { - console.error('缓存图片失败:', error) - // 缓存失败不影响显示,只是下载时需要重新获取 + // Cache failure doesn't affect display, only download needs to refetch } } const handleDownload = async () => { if (!resultImage.value) return - // 检查登录状态 + // Check login status if (!isLoggedIn.value) { message.warning(t('Please login to download')) showLoginModal.value = true @@ -654,10 +648,10 @@ const handleDownload = async () => { } try { - // 优先使用缓存的 blob URL + // Prefer cached blob URL let blobUrl = resultImageBlobUrl.value - // 如果没有缓存,则获取并缓存 + // If no cache, fetch and cache if (!blobUrl) { const response = await fetch(resultImage.value) if (!response.ok) { @@ -672,9 +666,8 @@ const handleDownload = async () => { link.href = blobUrl link.download = `removed-background-${Date.now()}.png` link.click() - // 不立即清理 blob URL,保留缓存供后续下载使用 + // Don't immediately clean up blob URL, keep cache for subsequent downloads } catch (error) { - console.error('下载失败:', error) message.error(t('Failed to download image')) } } @@ -683,7 +676,7 @@ const resetUpload = () => { if (uploadedImageUrl.value && uploadedImageUrl.value.startsWith('blob:')) { URL.revokeObjectURL(uploadedImageUrl.value) } - // 清理结果图片的 blob URL 缓存 + // Clean up result image blob URL cache if (resultImageBlobUrl.value) { URL.revokeObjectURL(resultImageBlobUrl.value) resultImageBlobUrl.value = '' @@ -709,10 +702,10 @@ const resetUpload = () => { const adjustContainerSize = async () => { await nextTick() - // 等待多个渲染周期确保 DOM 完全更新 + // Wait for multiple render cycles to ensure DOM is fully updated await new Promise(resolve => setTimeout(resolve, 0)) - // 处理对比视图容器 + // Handle comparison view container const container = comparisonContainerRef.value if (container) { const img = originalImageRef.value || resultImageRef.value @@ -746,7 +739,7 @@ const adjustContainerSize = async () => { } } - // 处理单图视图容器 + // Handle single image view container const singleWrapper = singleImageWrapperRef.value if (singleWrapper) { const img = singleImageRef.value @@ -906,13 +899,13 @@ const handleUrlSubmit = async () => { const originalFile = new File([blob], 'image-from-url', { type: blob.type }) - // 压缩图片到 1024x1024 + // Compress image to 1024x1024 try { const compressedFile = await compressImageFile(originalFile, { maxWidth: 1024, maxHeight: 1024, quality: 0.92, - mode: 'contain' // 等比缩放 + mode: 'contain' // Maintain aspect ratio }) uploadedImage.value = compressedFile @@ -920,12 +913,10 @@ const handleUrlSubmit = async () => { await handleRemoveBackground() } catch (error) { - console.error('图片压缩失败:', error) message.error(t('Image processing failed, please try again')) processing.value = false } } catch (error: any) { - console.error('加载图片URL失败:', error) let errorMessage = t('Failed to load image from URL') if (error.message?.includes('CORS')) { @@ -949,7 +940,7 @@ const selectHistoryItem = async (index: number) => { splitPosition.value = 0 uploadedImage.value = item.originalImageFile - // 缓存历史记录的结果图片 + // Cache result image from history if (item.resultImage) { await cacheResultImage(item.resultImage) } @@ -986,11 +977,11 @@ onMounted(async () => { window.addEventListener('resize', handleWindowResize) window.addEventListener('paste', handlePaste) - // 初始化认证状态 + // Initialize auth state await authStore.initAuth() - // 检测移动端 + // Detect mobile checkIsMobile() }) @@ -1000,7 +991,7 @@ onUnmounted(() => { if (uploadedImageUrl.value && uploadedImageUrl.value.startsWith('blob:')) { URL.revokeObjectURL(uploadedImageUrl.value) } - // 清理结果图片的 blob URL 缓存 + // Clean up result image blob URL cache if (resultImageBlobUrl.value) { URL.revokeObjectURL(resultImageBlobUrl.value) } @@ -1009,7 +1000,7 @@ onUnmounted(() => {