diff --git a/src/api/storage/index.ts b/src/api/storage/index.ts index 39969c9..e944536 100644 --- a/src/api/storage/index.ts +++ b/src/api/storage/index.ts @@ -310,3 +310,22 @@ export const queryThingDetailListApi = (tag_name: string, provider: string, buck hitSource: ["upload-file"], }); }; + +/** + * 获取单个照片url + * @param id + */ +export const getSingleImageApi = (id: number) => { + return service.Post('/api/auth/storage/image/url/single', { + id: id, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + }); +}; diff --git a/src/components/MyUI/CheckCard/CheckCard.vue b/src/components/MyUI/CheckCard/CheckCard.vue index 1f85f09..3af9363 100644 --- a/src/components/MyUI/CheckCard/CheckCard.vue +++ b/src/components/MyUI/CheckCard/CheckCard.vue @@ -47,7 +47,7 @@ const props = withDefaults(defineProps(), { iconPosition: 'top-left', margin: '16px', borderRadius: '8px', - backgroundColor: '#e5eeff', + backgroundColor: 'transparent', showHoverCircle: true, // 默认显示悬停圆环 iconSize: 24, // 默认图标大小 showSelectedEffect: true, // 默认显示选中效果 @@ -100,6 +100,7 @@ function toggleSelection() { .check-card.selected { border: 1px solid rgba(125, 167, 255, 0.68); box-shadow: 0 0 2px rgba(77, 167, 255, 0.89); + background-color: #e5eeff; } .card-content { diff --git a/src/store/modules/uploadStore.ts b/src/store/modules/uploadStore.ts index a1b53f6..18962fc 100644 --- a/src/store/modules/uploadStore.ts +++ b/src/store/modules/uploadStore.ts @@ -10,6 +10,9 @@ interface UploadPredictResult { height: number | null; latitude: number | null; longitude: number | null; + thumb_w: number | null; + thumb_h: number | null; + thumb_size: number | null; } @@ -28,6 +31,9 @@ export const useUploadStore = defineStore( height: null, latitude: null, longitude: null, + thumb_w: null, + thumb_h: null, + thumb_size: null, }); /** @@ -49,6 +55,10 @@ export const useUploadStore = defineStore( predictResult.width = null; predictResult.height = null; predictResult.latitude = null; + predictResult.longitude = null; + predictResult.thumb_w = null; + predictResult.thumb_h = null; + predictResult.thumb_size = null; } diff --git a/src/utils/imageUtils/convertToJPEG.ts b/src/utils/imageUtils/convertToJPEG.ts new file mode 100644 index 0000000..a71d395 --- /dev/null +++ b/src/utils/imageUtils/convertToJPEG.ts @@ -0,0 +1,59 @@ +export function convertToImageBasedOnType(file: File): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = (e) => { + const img = new Image(); + img.src = e.target?.result as string; + + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + if (!ctx) { + reject('Failed to get canvas context'); + return; + } + + canvas.width = img.width; + canvas.height = img.height; + ctx.drawImage(img, 0, 0); + + // 根据文件的 MIME 类型判断是否需要转换 + const mimeType = file.type; + + if (mimeType === 'image/png') { + // 如果是 PNG 格式,转换为 JPEG 格式 + canvas.toBlob((blob) => { + if (blob) { + resolve(blob); // 返回 JPEG 格式的图像 + } else { + reject('Failed to convert to JPEG'); + } + }, 'image/jpeg'); + } else if (mimeType === 'image/jpeg') { + // 如果是 JPEG 格式,不需要转换 + canvas.toBlob((blob) => { + if (blob) { + resolve(blob); // 返回 JPEG 格式的图像 + } else { + reject('Failed to convert to JPEG'); + } + }, 'image/jpeg'); + } else { + reject('Unsupported image format'); + } + }; + + img.onerror = () => { + reject('Failed to load image'); + }; + }; + + reader.onerror = () => { + reject('Failed to read file'); + }; + + reader.readAsDataURL(file); // 读取文件为 DataURL + }); +} diff --git a/src/utils/imageUtils/generateThumb.ts b/src/utils/imageUtils/generateThumb.ts new file mode 100644 index 0000000..aebbebf --- /dev/null +++ b/src/utils/imageUtils/generateThumb.ts @@ -0,0 +1,124 @@ +// 定义返回数据的类型 +interface ThumbnailResult { + binaryData: Blob | null; + width: number; + height: number; + size: number; // 添加 size 字段,表示缩略图的大小 +} + +// 工具函数:生成视频或图片缩略图并返回二进制数据(Blob)及宽高和大小 +export const generateThumbnail = (file: File): Promise => { + return new Promise((resolve, reject) => { + const fileType = file.type.toLowerCase(); + const supportedImageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/bmp']; + const supportedVideoTypes = ['video/mp4', 'video/webm', 'video/ogg']; + + // 判断文件类型 + if (supportedImageTypes.includes(fileType)) { + // 如果是图片文件 + createImageThumbnail(file) + .then((result) => resolve(result)) + .catch(reject); + } else if (supportedVideoTypes.includes(fileType)) { + // 如果是视频文件 + createVideoThumbnail(file) + .then((result) => resolve(result)) + .catch(reject); + } else { + reject(new Error('不支持的文件类型')); + } + }); +}; + +// 生成图片的缩略图 +const createImageThumbnail = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (event) => { + const img = new Image(); + img.onload = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + + const fixedHeight = 200; + const scaleFactor = fixedHeight / img.height; + const width = img.width * scaleFactor; + const height = fixedHeight; + + canvas.width = width; + canvas.height = height; + ctx?.drawImage(img, 0, 0, width, height); + + // 转换为二进制数据(Blob) + canvas.toBlob((blob) => { + if (blob) { + resolve({ + binaryData: blob, + width: width, + height: height, + size: blob.size, // 获取缩略图的大小 + }); + } else { + reject(new Error('生成二进制数据失败')); + } + }, file.type); + }; + img.src = event.target?.result as string; + }; + reader.onerror = () => { + reject(new Error('读取文件失败')); + }; + + reader.readAsDataURL(file); + }); +}; + +// 生成视频的缩略图 +const createVideoThumbnail = (file: File): Promise => { + return new Promise((resolve, reject) => { + const videoElement = document.createElement('video'); + const objectURL = URL.createObjectURL(file); + videoElement.src = objectURL; + + videoElement.onloadeddata = () => { + // 在第一帧加载完成时获取图像 + videoElement.currentTime = 2; // 设置视频播放位置为 2 秒(可调节) + + videoElement.onseeked = () => { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + if (ctx) { + // 将视频帧绘制到 canvas 上 + const fixedHeight = 200; + const scaleFactor = fixedHeight / videoElement.videoHeight; + const width = videoElement.videoWidth * scaleFactor; + const height = fixedHeight; + + canvas.width = width; + canvas.height = height; + ctx.drawImage(videoElement, 0, 0, width, height); + + // 将 canvas 转为图像 URL + canvas.toBlob((blob) => { + if (blob) { + resolve({ + binaryData: blob, + width: width, + height: height, + size: blob.size, // 获取缩略图的大小 + }); + } else { + reject(new Error('生成视频缩略图失败')); + } + }); + } else { + reject(new Error('无法获取 canvas 上下文')); + } + }; + }; + + videoElement.onerror = () => { + reject(new Error('加载视频失败')); + }; + }); +}; diff --git a/src/views/Album/LocationAlbum/LocationAlbumDetail.vue b/src/views/Album/LocationAlbum/LocationAlbumDetail.vue index 25932f2..a14aba4 100644 --- a/src/views/Album/LocationAlbum/LocationAlbumDetail.vue +++ b/src/views/Album/LocationAlbum/LocationAlbumDetail.vue @@ -2,7 +2,7 @@
- 地点 + 地点 > 乌鲁木齐
@@ -11,13 +11,74 @@ 共12张照片
- +
+
+ {{ itemList.date }} + + + + + +
+