diff --git a/apps/desktop/src/components/ModelImageGallery.tsx b/apps/desktop/src/components/ModelImageGallery.tsx index 3acaefa..6fdd4d6 100644 --- a/apps/desktop/src/components/ModelImageGallery.tsx +++ b/apps/desktop/src/components/ModelImageGallery.tsx @@ -9,10 +9,10 @@ import { Search } from 'lucide-react'; import { ModelPhoto, PhotoType } from '../types/model'; -import { convertFileSrc } from '@tauri-apps/api/core'; import { ModelImageUploader } from './ModelImageUploader'; import { ModelImagePreviewModal } from './ModelImagePreviewModal'; import { DeleteConfirmDialog } from './DeleteConfirmDialog'; +import { getImageSrc } from '../utils/imagePathUtils'; interface ModelImageGalleryProps { photos: ModelPhoto[]; @@ -175,6 +175,8 @@ export const ModelImageGallery: React.FC = ({ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; }; + + return (
{/* 头部工具栏 */} @@ -277,7 +279,7 @@ export const ModelImageGallery: React.FC = ({ {/* 图片 */}
{photo.file_name} @@ -346,7 +348,7 @@ export const ModelImageGallery: React.FC = ({ {/* 缩略图 */}
{photo.file_name} diff --git a/apps/desktop/src/components/ModelImagePreviewModal.tsx b/apps/desktop/src/components/ModelImagePreviewModal.tsx index 21d0236..8f59e37 100644 --- a/apps/desktop/src/components/ModelImagePreviewModal.tsx +++ b/apps/desktop/src/components/ModelImagePreviewModal.tsx @@ -17,7 +17,7 @@ import { Tag } from 'lucide-react'; import { ModelPhoto, PhotoType } from '../types/model'; -import { convertFileSrc } from '@tauri-apps/api/core'; +import { getImageSrc } from '../utils/imagePathUtils'; interface ModelImagePreviewModalProps { photos: ModelPhoto[]; @@ -181,9 +181,11 @@ export const ModelImagePreviewModal: React.FC = ({ return new Date(dateString).toLocaleString('zh-CN'); }; + + if (!isOpen || !currentPhoto) return null; - const imageUrl = convertFileSrc(currentPhoto.file_path); + const imageUrl = getImageSrc(currentPhoto.file_path); return (
= ({ }`} > {photo.file_name} diff --git a/apps/desktop/src/utils/__tests__/imagePathUtils.test.ts b/apps/desktop/src/utils/__tests__/imagePathUtils.test.ts new file mode 100644 index 0000000..018cda0 --- /dev/null +++ b/apps/desktop/src/utils/__tests__/imagePathUtils.test.ts @@ -0,0 +1,68 @@ +import { describe, it, expect, vi } from 'vitest'; +import { getImageSrc, isCloudUrl, isLocalPath } from '../imagePathUtils'; + +// Mock Tauri API +vi.mock('@tauri-apps/api/core', () => ({ + convertFileSrc: vi.fn((path: string) => `tauri://localhost${path}`) +})); + +describe('imagePathUtils', () => { + describe('isCloudUrl', () => { + it('应该正确识别HTTPS URL', () => { + expect(isCloudUrl('https://cdn.roasmax.cn/models/photos/model-1/image.jpg')).toBe(true); + }); + + it('应该正确识别HTTP URL', () => { + expect(isCloudUrl('http://example.com/image.jpg')).toBe(true); + }); + + it('应该正确识别本地路径', () => { + expect(isCloudUrl('/local/path/to/image.jpg')).toBe(false); + expect(isCloudUrl('C:\\Windows\\path\\to\\image.jpg')).toBe(false); + expect(isCloudUrl('./relative/path/image.jpg')).toBe(false); + }); + }); + + describe('isLocalPath', () => { + it('应该正确识别本地路径', () => { + expect(isLocalPath('/local/path/to/image.jpg')).toBe(true); + expect(isLocalPath('C:\\Windows\\path\\to\\image.jpg')).toBe(true); + expect(isLocalPath('./relative/path/image.jpg')).toBe(true); + }); + + it('应该正确识别云端URL', () => { + expect(isLocalPath('https://cdn.roasmax.cn/models/photos/model-1/image.jpg')).toBe(false); + expect(isLocalPath('http://example.com/image.jpg')).toBe(false); + }); + }); + + describe('getImageSrc', () => { + it('应该直接返回HTTPS URL', () => { + const cloudUrl = 'https://cdn.roasmax.cn/models/photos/model-1/image.jpg'; + expect(getImageSrc(cloudUrl)).toBe(cloudUrl); + }); + + it('应该直接返回HTTP URL', () => { + const cloudUrl = 'http://example.com/image.jpg'; + expect(getImageSrc(cloudUrl)).toBe(cloudUrl); + }); + + it('应该转换本地路径', () => { + const localPath = '/local/path/to/image.jpg'; + const result = getImageSrc(localPath); + expect(result).toBe('tauri://localhost/local/path/to/image.jpg'); + }); + + it('应该转换Windows本地路径', () => { + const localPath = 'C:\\Windows\\path\\to\\image.jpg'; + const result = getImageSrc(localPath); + expect(result).toBe('tauri://localhostC:\\Windows\\path\\to\\image.jpg'); + }); + + it('应该转换相对路径', () => { + const localPath = './relative/path/image.jpg'; + const result = getImageSrc(localPath); + expect(result).toBe('tauri://localhost./relative/path/image.jpg'); + }); + }); +}); diff --git a/apps/desktop/src/utils/imagePathUtils.ts b/apps/desktop/src/utils/imagePathUtils.ts new file mode 100644 index 0000000..2834494 --- /dev/null +++ b/apps/desktop/src/utils/imagePathUtils.ts @@ -0,0 +1,33 @@ +import { convertFileSrc } from '@tauri-apps/api/core'; + +/** + * 处理图片路径,区分本地路径和云端URL + * @param filePath 文件路径或URL + * @returns 处理后的图片源地址 + */ +export const getImageSrc = (filePath: string): string => { + // 如果是云端URL(以http://或https://开头),直接返回 + if (filePath.startsWith('http://') || filePath.startsWith('https://')) { + return filePath; + } + // 如果是本地路径,使用convertFileSrc转换 + return convertFileSrc(filePath); +}; + +/** + * 检查路径是否为云端URL + * @param filePath 文件路径 + * @returns 是否为云端URL + */ +export const isCloudUrl = (filePath: string): boolean => { + return filePath.startsWith('http://') || filePath.startsWith('https://'); +}; + +/** + * 检查路径是否为本地文件路径 + * @param filePath 文件路径 + * @returns 是否为本地路径 + */ +export const isLocalPath = (filePath: string): boolean => { + return !isCloudUrl(filePath); +};