From d5fd62624288ef5afaba08f23db7c4280df470d7 Mon Sep 17 00:00:00 2001 From: landaiqing Date: Thu, 13 Feb 2025 18:19:39 +0800 Subject: [PATCH] :sparkles: detail list development --- components.d.ts | 2 + src/api/storage/index.ts | 149 ++++++++++++ src/components/MyUI/PhotoStack/PhotoStack.vue | 2 +- src/constant/coco_ssd_label_category.ts | 15 +- src/store/modules/uploadStore.ts | 16 +- .../LocationAlbum/LocationAlbumDetail.vue | 87 ++++++- .../Album/LocationAlbum/LocationAlbumList.vue | 135 +++++++---- .../Album/PeopleAlbum/PeopleAlbumDetail.vue | 90 +++++++- .../Album/PeopleAlbum/PeopleAlbumList.vue | 12 + src/views/Album/Phoalbum/PhoalbumDetail.vue | 214 +++++++++++++++++- src/views/Album/Phoalbum/PhoalbumList.vue | 16 +- .../Album/ThingAlbum/ThingAlbumDetail.vue | 87 ++++++- src/views/Album/ThingAlbum/ThingAlbumList.vue | 146 ++++++++---- src/views/Photograph/AllPhoto/AllPhoto.vue | 121 +--------- .../Photograph/ImageToolbar/ImageToolbar.vue | 130 +++++++++++ .../Photograph/ImageUpload/ImageUpload.vue | 23 +- .../Photograph/RecentUpload/RecentUpload.vue | 120 ++++------ 17 files changed, 1048 insertions(+), 317 deletions(-) create mode 100644 src/views/Photograph/ImageToolbar/ImageToolbar.vue diff --git a/components.d.ts b/components.d.ts index 94929a0..a5ecc16 100644 --- a/components.d.ts +++ b/components.d.ts @@ -101,11 +101,13 @@ declare module 'vue' { GradientText: typeof import('./src/components/MyUI/GradientText/GradientText.vue')['default'] Image: typeof import('./src/components/MyUI/Image/Image.vue')['default'] ImageShare: typeof import('./src/views/ImageShare/ImageShare.vue')['default'] + ImageToolbar: typeof import('./src/views/Photograph/ImageToolbar/ImageToolbar.vue')['default'] ImageUpload: typeof import('./src/views/Photograph/ImageUpload/ImageUpload.vue')['default'] ImageWaterfall: typeof import('./src/components/MyUI/Waterfall/ImageWaterfall.vue')['default'] Input: typeof import('./src/components/MyUI/Input/Input.vue')['default'] InputSearch: typeof import('./src/components/MyUI/InputSearch/InputSearch.vue')['default'] LandingPage: typeof import('./src/views/Landing/LandingPage.vue')['default'] + LeftOutlined: typeof import('@ant-design/icons-vue')['LeftOutlined'] List: typeof import('./src/components/MyUI/List/List.vue')['default'] LoadingBar: typeof import('./src/components/MyUI/LoadingBar/LoadingBar.vue')['default'] LoadingGraphic: typeof import('./src/components/LoadingGraphic/LoadingGraphic.vue')['default'] diff --git a/src/api/storage/index.ts b/src/api/storage/index.ts index c93c4a3..39969c9 100644 --- a/src/api/storage/index.ts +++ b/src/api/storage/index.ts @@ -33,6 +33,29 @@ export const getFaceSamplesList = (type: number) => { hitSource: ["modify-face-sample-name", "modify-face-sample-type"], }); }; +/** + * 获取人脸样本详情列表 + * @param face_id + * @param provider + * @param bucket + */ +export const getFaceSamplesDetailList = (face_id: number, provider: string, bucket: string) => { + return service.Post('/api/auth/storage/face/detail/list', { + face_id: face_id, + provider: provider, + bucket: bucket, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["modify-face-sample-name", "modify-face-sample-type"], + }); +}; /** * 修改人脸样本名称 * @param id @@ -103,6 +126,28 @@ export const albumListApi = (type: string, sort: boolean) => { hitSource: ["create-album", "rename-album", "delete-album"], }); }; +/** + * 获取相册详情列表 + * @param id + * @param provider + * @param bucket + */ +export const queryAlbumDetailListApi = (id: number, provider: string, bucket: string) => { + return service.Post('/api/auth/storage/album/detail/list', { + id: id, + provider: provider, + bucket: bucket, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + }); +}; /** * 重命名相册 @@ -161,3 +206,107 @@ export const queryAllImagesApi = (type: string, sort: boolean, provider: string, hitSource: ["upload-file"], }); }; + + +/** + * 获取最近照片列表 + */ +export const queryRecentImagesApi = () => { + return service.Post('/api/auth/storage/image/recent/list', {}, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["upload-file"], + }); +}; +/** + * 获取地址相册列表 + */ +export const queryLocationAlbumApi = (provider: string, bucket: string) => { + return service.Post('/api/auth/storage/image/location/list', { + provider: provider, + bucket: bucket, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["upload-file"], + }); +}; +/** + * 获取地址相册列表详情 + * @param id + * @param provider + * @param bucket + */ +export const queryLocationDetailListApi = (id: number, provider: string, bucket: string) => { + return service.Post('/api/auth/storage/image/location/detail/list', { + provider: provider, + bucket: bucket, + id: id, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["upload-file"], + }); +}; + +/** + * 获取标签相册列表 + */ +export const queryThingAlbumApi = (provider: string, bucket: string) => { + return service.Post('/api/auth/storage/image/thing/list', { + provider: provider, + bucket: bucket, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["upload-file"], + }); +}; + +/** + * 获取事物标签列表详情 + * @param tag_name + * @param provider + * @param bucket + */ +export const queryThingDetailListApi = (tag_name: string, provider: string, bucket: string) => { + return service.Post('/api/auth/storage/image/thing/detail/list', { + provider: provider, + bucket: bucket, + tag_name: tag_name, + }, { + cacheFor: { + expire: 60 * 60 * 24 * 7, + mode: "restore", + }, + meta: { + ignoreToken: false, + signature: false, + }, + hitSource: ["upload-file"], + }); +}; diff --git a/src/components/MyUI/PhotoStack/PhotoStack.vue b/src/components/MyUI/PhotoStack/PhotoStack.vue index a7badf3..b281e94 100644 --- a/src/components/MyUI/PhotoStack/PhotoStack.vue +++ b/src/components/MyUI/PhotoStack/PhotoStack.vue @@ -25,7 +25,7 @@ const imageSrc = computed(() => props.src || props.defaultSrc); height: 180px; vertical-align: bottom; border: 5px #fff solid; - border-radius: 10px; + border-radius: 15px; box-sizing: border-box; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.4); } diff --git a/src/constant/coco_ssd_label_category.ts b/src/constant/coco_ssd_label_category.ts index 8ca1f42..f51e20c 100644 --- a/src/constant/coco_ssd_label_category.ts +++ b/src/constant/coco_ssd_label_category.ts @@ -9,14 +9,14 @@ export const CATEGORIES = { ELECTRONICS: {en: 'electronics', zh: '电子产品'}, EVERYDAY_ITEMS: {en: 'everyday_items', zh: '日常物品'}, HOUSEHOLD: {en: 'household', zh: '家居用品'}, - HUMAN: {en: 'human', zh: '人类'}, + HUMAN: {en: 'human', zh: '人物'}, } as const; // 为每个标签提供中文名称的映射 export const LABELS = { // Human 人类 - 'person': {en: 'person', zh: '人'}, + 'person': {en: 'person', zh: '人物'}, // Vehicles 交通工具 'bicycle': {en: 'bicycle', zh: '自行车'}, @@ -237,6 +237,17 @@ export function getLabelName(label: string, lang: 'en' | 'zh' = 'en'): string | return labelInfo ? labelInfo[lang] : undefined; } +// 获取标签的中文名称 +export const getZhCategoryNameByEnName = (enName: string): string | undefined => { + const category = Object.values(CATEGORIES).find(cat => cat.en.toLowerCase() === enName.toLowerCase()); + return category?.zh; +}; +// 获取标签的中文名称 +export const getZhLabelNameByEnName = (enName: string): string | undefined => { + const labelInfo = LABELS[enName.toLowerCase()]; + return labelInfo?.zh; +}; + // 使用示例 // console.log(getLabelName('person')); // 输出: 'person' (英文) // console.log(getLabelName('person', 'zh')); // 输出: '人' (中文) diff --git a/src/store/modules/uploadStore.ts b/src/store/modules/uploadStore.ts index 4f019ff..a1b53f6 100644 --- a/src/store/modules/uploadStore.ts +++ b/src/store/modules/uploadStore.ts @@ -2,13 +2,14 @@ import localforage from 'localforage'; interface UploadPredictResult { isAnime: boolean; - objectArray: string[] | unknown[]; + tagName: string | null; landscape: 'building' | 'forest' | 'glacier' | 'mountain' | 'sea' | 'street' | null; isScreenshot: boolean; topCategory: string | undefined; - exif: object | ""; width: number | null; height: number | null; + latitude: number | null; + longitude: number | null; } @@ -19,13 +20,14 @@ export const useUploadStore = defineStore( const predictResult = reactive({ isAnime: false, - objectArray: [], + tagName: null, landscape: null, isScreenshot: false, topCategory: '', - exif: "", width: null, height: null, + latitude: null, + longitude: null, }); /** @@ -40,11 +42,13 @@ export const useUploadStore = defineStore( */ function clearPredictResult() { predictResult.isAnime = false; - predictResult.objectArray = []; + predictResult.tagName = null; predictResult.landscape = null; predictResult.isScreenshot = false; predictResult.topCategory = ''; - predictResult.exif = ""; + predictResult.width = null; + predictResult.height = null; + predictResult.latitude = null; } diff --git a/src/views/Album/LocationAlbum/LocationAlbumDetail.vue b/src/views/Album/LocationAlbum/LocationAlbumDetail.vue index 0a8d203..25932f2 100644 --- a/src/views/Album/LocationAlbum/LocationAlbumDetail.vue +++ b/src/views/Album/LocationAlbum/LocationAlbumDetail.vue @@ -1,11 +1,92 @@ + + diff --git a/src/views/Album/LocationAlbum/LocationAlbumList.vue b/src/views/Album/LocationAlbum/LocationAlbumList.vue index c54e33a..89d2f75 100644 --- a/src/views/Album/LocationAlbum/LocationAlbumList.vue +++ b/src/views/Album/LocationAlbum/LocationAlbumList.vue @@ -2,27 +2,49 @@
地点 - 你一共在2个地点留下足迹 + 你一共在{{ locationAlbums ? locationAlbums.length : 0 }}个地点留下足迹
-
- -
- 乌鲁木齐市 - --- - 16张照片 +
+ {{ item.location }} +
+
+ +
+ {{ itemList.city }} + --- + {{ itemList.total }}张照片 +
+
diff --git a/src/views/Album/PeopleAlbum/PeopleAlbumList.vue b/src/views/Album/PeopleAlbum/PeopleAlbumList.vue index 4ae9ff1..5408604 100644 --- a/src/views/Album/PeopleAlbum/PeopleAlbumList.vue +++ b/src/views/Album/PeopleAlbum/PeopleAlbumList.vue @@ -55,6 +55,7 @@ { getFaceList(); }); diff --git a/src/views/Album/Phoalbum/PhoalbumDetail.vue b/src/views/Album/Phoalbum/PhoalbumDetail.vue index 2db69d4..abf44e6 100644 --- a/src/views/Album/Phoalbum/PhoalbumDetail.vue +++ b/src/views/Album/Phoalbum/PhoalbumDetail.vue @@ -1,9 +1,219 @@ - diff --git a/src/views/Album/Phoalbum/PhoalbumList.vue b/src/views/Album/Phoalbum/PhoalbumList.vue index 025b7ee..498c838 100644 --- a/src/views/Album/Phoalbum/PhoalbumList.vue +++ b/src/views/Album/Phoalbum/PhoalbumList.vue @@ -60,6 +60,7 @@
@@ -69,8 +70,8 @@
- - + + @@ -208,6 +209,17 @@ async function deleteAlbum(id: number) { } } +const route = useRoute(); +const router = useRouter(); + +/** + * 点击相册跳转到详情页 + * @param id + */ +function handleClick(id: number) { + router.push({path: route.path + `/${id}`}); +} + onMounted(() => { getAlbumList("0", selecetedKey.value); }); diff --git a/src/views/Album/ThingAlbum/ThingAlbumDetail.vue b/src/views/Album/ThingAlbum/ThingAlbumDetail.vue index 0a8d203..a9bfb92 100644 --- a/src/views/Album/ThingAlbum/ThingAlbumDetail.vue +++ b/src/views/Album/ThingAlbum/ThingAlbumDetail.vue @@ -1,11 +1,92 @@ + + diff --git a/src/views/Album/ThingAlbum/ThingAlbumList.vue b/src/views/Album/ThingAlbum/ThingAlbumList.vue index 8246f1e..7b1bf1b 100644 --- a/src/views/Album/ThingAlbum/ThingAlbumList.vue +++ b/src/views/Album/ThingAlbum/ThingAlbumList.vue @@ -6,13 +6,18 @@
- 动物 -
- -
- - --- - 16张照片 +
+ {{ getZhCategoryNameByEnName(item.category) }} +
+
+ +
+ {{ getZhLabelNameByEnName(tags.tag_name) }} + --- + {{ tags.tag_count }}张照片 +
+
@@ -20,6 +25,35 @@ diff --git a/src/views/Photograph/ImageUpload/ImageUpload.vue b/src/views/Photograph/ImageUpload/ImageUpload.vue index 9047e74..d46a5c8 100644 --- a/src/views/Photograph/ImageUpload/ImageUpload.vue +++ b/src/views/Photograph/ImageUpload/ImageUpload.vue @@ -145,9 +145,10 @@ async function beforeUpload(file: File, fileList: File[]) { } // 提取 EXIF 数据 - const exifData = await extractAllExifData(file); - if (exifData) { - upload.predictResult.exif = exifData ? exifData : ""; + const gpsData = await extractGPSExifData(file); + if (gpsData) { + upload.predictResult.longitude = gpsData.longitude; + upload.predictResult.latitude = gpsData.latitude; } // 判断是否为截图 @@ -177,13 +178,13 @@ async function beforeUpload(file: File, fileList: File[]) { // 如果只有一个结果,直接取第一个 if (cocoResults.length === 1) { upload.predictResult.topCategory = getCategoryByLabel(cocoResults[0].class); + upload.predictResult.tagName = cocoResults[0].class; } else { // 多个结果时,按 score 排序,取置信度最高的结果 const sortedResults = cocoResults.sort((a, b) => b.score - a.score); upload.predictResult.topCategory = getCategoryByLabel(sortedResults[0].class); + upload.predictResult.tagName = sortedResults[0].class; } - const classSet = new Set(cocoResults.map(result => result.class)); - upload.predictResult.objectArray = Array.from(classSet); } upload.predictResult.landscape = landscape as 'building' | 'forest' | 'glacier' | 'mountain' | 'sea' | 'street' | null; @@ -268,7 +269,7 @@ function removeFile(file: any) { * @param {File} file - 图片文件 * @returns {Promise} - 返回所有 EXIF 数据或 null(如果格式不支持或提取失败) */ -async function extractAllExifData(file) { +async function extractGPSExifData(file) { const supportedFormats = ['image/jpeg', 'image/tiff', 'image/iiq', 'image/heif', 'image/heic', 'image/avif', 'image/png']; // 判断文件格式是否支持 @@ -276,11 +277,11 @@ async function extractAllExifData(file) { return null; } - try { - // 提取所有 EXIF 数据 - return await exifr.parse(file, {ifd0: false, exif: true} as any); - } catch (error) { - console.error("提取 EXIF 数据失败:", error); + // 提取GPS EXIF 数据 + let {latitude, longitude} = await exifr.gps(file); + if (latitude && longitude) { + return {latitude, longitude}; + } else { return null; } } diff --git a/src/views/Photograph/RecentUpload/RecentUpload.vue b/src/views/Photograph/RecentUpload/RecentUpload.vue index 90c153b..c7792d2 100644 --- a/src/views/Photograph/RecentUpload/RecentUpload.vue +++ b/src/views/Photograph/RecentUpload/RecentUpload.vue @@ -14,99 +14,65 @@ 创建相册
+
- 2024年12月27日 星期日 - - - - - +
+ {{ itemList.date }} + + + + + +