✨ optimized image list interface
This commit is contained in:
@@ -310,3 +310,22 @@ export const queryThingDetailListApi = (tag_name: string, provider: string, buck
|
|||||||
hitSource: ["upload-file"],
|
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,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@@ -47,7 +47,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
iconPosition: 'top-left',
|
iconPosition: 'top-left',
|
||||||
margin: '16px',
|
margin: '16px',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
backgroundColor: '#e5eeff',
|
backgroundColor: 'transparent',
|
||||||
showHoverCircle: true, // 默认显示悬停圆环
|
showHoverCircle: true, // 默认显示悬停圆环
|
||||||
iconSize: 24, // 默认图标大小
|
iconSize: 24, // 默认图标大小
|
||||||
showSelectedEffect: true, // 默认显示选中效果
|
showSelectedEffect: true, // 默认显示选中效果
|
||||||
@@ -100,6 +100,7 @@ function toggleSelection() {
|
|||||||
.check-card.selected {
|
.check-card.selected {
|
||||||
border: 1px solid rgba(125, 167, 255, 0.68);
|
border: 1px solid rgba(125, 167, 255, 0.68);
|
||||||
box-shadow: 0 0 2px rgba(77, 167, 255, 0.89);
|
box-shadow: 0 0 2px rgba(77, 167, 255, 0.89);
|
||||||
|
background-color: #e5eeff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
|
@@ -10,6 +10,9 @@ interface UploadPredictResult {
|
|||||||
height: number | null;
|
height: number | null;
|
||||||
latitude: number | null;
|
latitude: number | null;
|
||||||
longitude: 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,
|
height: null,
|
||||||
latitude: null,
|
latitude: null,
|
||||||
longitude: null,
|
longitude: null,
|
||||||
|
thumb_w: null,
|
||||||
|
thumb_h: null,
|
||||||
|
thumb_size: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,6 +55,10 @@ export const useUploadStore = defineStore(
|
|||||||
predictResult.width = null;
|
predictResult.width = null;
|
||||||
predictResult.height = null;
|
predictResult.height = null;
|
||||||
predictResult.latitude = null;
|
predictResult.latitude = null;
|
||||||
|
predictResult.longitude = null;
|
||||||
|
predictResult.thumb_w = null;
|
||||||
|
predictResult.thumb_h = null;
|
||||||
|
predictResult.thumb_size = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
59
src/utils/imageUtils/convertToJPEG.ts
Normal file
59
src/utils/imageUtils/convertToJPEG.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
export function convertToImageBasedOnType(file: File): Promise<Blob> {
|
||||||
|
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
|
||||||
|
});
|
||||||
|
}
|
124
src/utils/imageUtils/generateThumb.ts
Normal file
124
src/utils/imageUtils/generateThumb.ts
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// 定义返回数据的类型
|
||||||
|
interface ThumbnailResult {
|
||||||
|
binaryData: Blob | null;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
size: number; // 添加 size 字段,表示缩略图的大小
|
||||||
|
}
|
||||||
|
|
||||||
|
// 工具函数:生成视频或图片缩略图并返回二进制数据(Blob)及宽高和大小
|
||||||
|
export const generateThumbnail = (file: File): Promise<ThumbnailResult> => {
|
||||||
|
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<ThumbnailResult> => {
|
||||||
|
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<ThumbnailResult> => {
|
||||||
|
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('加载视频失败'));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="location-album-detail">
|
<div class="location-album-detail">
|
||||||
<div class="location-album-detail-header">
|
<div class="location-album-detail-header">
|
||||||
<div class="location-detail-content-nav">
|
<div class="location-detail-content-nav">
|
||||||
<AButton size="large" type="text" class="location-detail-content-nav-title">地点</AButton>
|
<AButton size="large" type="text" class="location-detail-content-nav-title" @click="goBack">地点</AButton>
|
||||||
<span class="location-detail-content-nav-separator"> > </span>
|
<span class="location-detail-content-nav-separator"> > </span>
|
||||||
<span class="location-detail-content-nav-name">乌鲁木齐</span>
|
<span class="location-detail-content-nav-name">乌鲁木齐</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -11,13 +11,74 @@
|
|||||||
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="location-album-detail-list">
|
<div class="location-album-detail-list">
|
||||||
|
<div style="width:100%;height:100%;">
|
||||||
|
<div v-for="(itemList, index) in albumList" :key="index">
|
||||||
|
<span style="margin-left: 10px;font-size: 13px">{{ itemList.date }}</span>
|
||||||
|
<AImagePreviewGroup>
|
||||||
|
<Vue3JustifiedLayout v-model:list="itemList.list" :options="options">
|
||||||
|
<template #default="{ item }">
|
||||||
|
<CheckCard :key="index"
|
||||||
|
class="photo-item"
|
||||||
|
margin="0"
|
||||||
|
border-radius="0"
|
||||||
|
v-model="selected"
|
||||||
|
:showHoverCircle="true"
|
||||||
|
:iconSize="20"
|
||||||
|
:showSelectedEffect="true"
|
||||||
|
:value="item.id">
|
||||||
|
<AImage :src="item.thumbnail"
|
||||||
|
:alt="item.file_name"
|
||||||
|
:key="index"
|
||||||
|
:height="200"
|
||||||
|
:previewMask="false"
|
||||||
|
:preview="{
|
||||||
|
src: item.url,
|
||||||
|
}"
|
||||||
|
loading="lazy"/>
|
||||||
|
</CheckCard>
|
||||||
|
</template>
|
||||||
|
</Vue3JustifiedLayout>
|
||||||
|
</AImagePreviewGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import Vue3JustifiedLayout from "vue3-justified-layout";
|
||||||
|
import 'vue3-justified-layout/dist/style.css';
|
||||||
|
import {queryLocationDetailListApi} from "@/api/storage";
|
||||||
|
|
||||||
|
const selected = ref<(string | number)[]>([]);
|
||||||
|
const albumList = ref<any[]>([]);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const options = reactive({
|
||||||
|
targetRowHeight: 200 // 高度
|
||||||
|
});
|
||||||
|
|
||||||
|
async function getImageList(id: number) {
|
||||||
|
const res: any = await queryLocationDetailListApi(id, "ali", "schisandra-album");
|
||||||
|
console.log(res);
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
albumList.value = res.data.records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const idParam = route.params.id;
|
||||||
|
const albumId = Array.isArray(idParam) ? idParam[0] : idParam;
|
||||||
|
getImageList(parseInt(albumId, 10));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回上一页
|
||||||
|
*/
|
||||||
|
function goBack(): void {
|
||||||
|
router.go(-1);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.location-album-detail {
|
.location-album-detail {
|
||||||
@@ -47,7 +108,7 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
width: 1000%;
|
width: 1000%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
gap: 10px;
|
gap: 5px;
|
||||||
|
|
||||||
.location-detail-content-nav-title {
|
.location-detail-content-nav-title {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
@@ -75,7 +136,7 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
margin-left: 15px;
|
margin-left: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
@@ -83,8 +144,6 @@
|
|||||||
.location-album-detail-list {
|
.location-album-detail-list {
|
||||||
width: 99%;
|
width: 99%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: 5px;
|
|
||||||
background: #e2e2e2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
<div class="people-album-detail">
|
<div class="people-album-detail">
|
||||||
<div class="people-album-detail-header">
|
<div class="people-album-detail-header">
|
||||||
<div class="people-album-detail-nav">
|
<div class="people-album-detail-nav">
|
||||||
<AButton type="text" size="large" class="people-album-detail-nav-button">
|
<AButton type="text" size="large" class="people-album-detail-nav-button" @click="goBack">
|
||||||
<template #icon>
|
<template #icon>
|
||||||
<LeftOutlined style="font-size: 13px;font-weight: bolder"/>
|
<LeftOutlined style="font-size: 13px;font-weight: bolder"/>
|
||||||
</template>
|
</template>
|
||||||
@@ -14,16 +14,79 @@
|
|||||||
<span style="font-size: 14px;color: #333333">张皓扬</span>
|
<span style="font-size: 14px;color: #333333">张皓扬</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ImageToolbar :selected="selected"/>
|
||||||
<div class="people-album-detail-info">
|
<div class="people-album-detail-info">
|
||||||
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="people-album-detail-list">
|
<div class="people-album-detail-list">
|
||||||
|
<div style="width:100%;height:100%;">
|
||||||
|
<div v-for="(itemList, index) in albumList" :key="index">
|
||||||
|
<span style="margin-left: 10px;font-size: 13px">{{ itemList.date }}</span>
|
||||||
|
<AImagePreviewGroup>
|
||||||
|
<Vue3JustifiedLayout v-model:list="itemList.list" :options="options">
|
||||||
|
<template #default="{ item }">
|
||||||
|
<CheckCard :key="index"
|
||||||
|
class="photo-item"
|
||||||
|
margin="0"
|
||||||
|
border-radius="0"
|
||||||
|
v-model="selected"
|
||||||
|
:showHoverCircle="true"
|
||||||
|
:iconSize="20"
|
||||||
|
:showSelectedEffect="true"
|
||||||
|
:value="item.id">
|
||||||
|
<AImage :src="item.thumbnail"
|
||||||
|
:alt="item.file_name"
|
||||||
|
:key="index"
|
||||||
|
:height="200"
|
||||||
|
:previewMask="false"
|
||||||
|
:preview="{
|
||||||
|
src: item.url,
|
||||||
|
}"
|
||||||
|
loading="lazy"/>
|
||||||
|
</CheckCard>
|
||||||
|
</template>
|
||||||
|
</Vue3JustifiedLayout>
|
||||||
|
</AImagePreviewGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import Vue3JustifiedLayout from "vue3-justified-layout";
|
||||||
|
import 'vue3-justified-layout/dist/style.css';
|
||||||
|
import {getFaceSamplesDetailList} from "@/api/storage";
|
||||||
|
import ImageToolbar from "@/views/Photograph/ImageToolbar/ImageToolbar.vue";
|
||||||
|
|
||||||
|
|
||||||
|
const selected = ref<(string | number)[]>([]);
|
||||||
|
const albumList = ref<any[]>([]);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const options = reactive({
|
||||||
|
targetRowHeight: 200 // 高度
|
||||||
|
});
|
||||||
|
|
||||||
|
async function getAlbumList(id: number) {
|
||||||
|
const res: any = await getFaceSamplesDetailList(id, "ali", "schisandra-album");
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
albumList.value = res.data.records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const idParam = route.params.id;
|
||||||
|
const albumId = Array.isArray(idParam) ? idParam[0] : idParam;
|
||||||
|
getAlbumList(parseInt(albumId, 10));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回上一页
|
||||||
|
*/
|
||||||
|
function goBack(): void {
|
||||||
|
router.go(-1);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.people-album-detail {
|
.people-album-detail {
|
||||||
@@ -62,6 +125,7 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
padding: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +153,6 @@
|
|||||||
.people-album-detail-list {
|
.people-album-detail-list {
|
||||||
width: 99%;
|
width: 99%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: 10px;
|
|
||||||
background: #e2e2e2;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -73,7 +73,7 @@
|
|||||||
<AAvatar :size="86" shape="circle" :src="item.face_image"/>
|
<AAvatar :size="86" shape="circle" :src="item.face_image"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="people-album-item-name" v-show="!item.face_name">
|
<div class="people-album-item-name" v-show="!item.face_name">
|
||||||
<AButton @click="showAddNameInput(index)" class="people-album-add-name"
|
<AButton @click.stop="showAddNameInput(index)" class="people-album-add-name"
|
||||||
v-show="item.showButton && !item.showInput"
|
v-show="item.showButton && !item.showInput"
|
||||||
type="link"
|
type="link"
|
||||||
size="small">
|
size="small">
|
||||||
@@ -82,11 +82,12 @@
|
|||||||
<AInput ref="addNameInput" v-model:value="addNameInputValue" v-show="item.showInput"
|
<AInput ref="addNameInput" v-model:value="addNameInputValue" v-show="item.showInput"
|
||||||
@blur="hideAddNameInput(index)" size="small"
|
@blur="hideAddNameInput(index)" size="small"
|
||||||
:maxlength="10"
|
:maxlength="10"
|
||||||
|
@click.stop
|
||||||
:placeholder="item.face_name"
|
:placeholder="item.face_name"
|
||||||
class="people-album-add-input">
|
class="people-album-add-input">
|
||||||
<template #suffix>
|
<template #suffix>
|
||||||
<AButton type="link" style="font-size: 12px;" size="small" @mousedown.prevent
|
<AButton type="link" style="font-size: 12px;" size="small" @mousedown.prevent
|
||||||
@click="modifyFaceName(item.id,index)">完成
|
@click.stop="modifyFaceName(item.id,index)">完成
|
||||||
</AButton>
|
</AButton>
|
||||||
</template>
|
</template>
|
||||||
</AInput>
|
</AInput>
|
||||||
|
@@ -59,12 +59,14 @@
|
|||||||
:iconSize="20"
|
:iconSize="20"
|
||||||
:showSelectedEffect="true"
|
:showSelectedEffect="true"
|
||||||
:value="item.id">
|
:value="item.id">
|
||||||
<AImage :src="item.url"
|
<AImage :src="item.thumbnail"
|
||||||
:alt="item.file_name"
|
:alt="item.file_name"
|
||||||
:key="index"
|
:key="index"
|
||||||
style="height: 200px"
|
:height="200"
|
||||||
:previewMask="false"
|
:previewMask="false"
|
||||||
fallback="data:image/png;base64,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"
|
:preview="{
|
||||||
|
src: item.url,
|
||||||
|
}"
|
||||||
loading="lazy"/>
|
loading="lazy"/>
|
||||||
</CheckCard>
|
</CheckCard>
|
||||||
</template>
|
</template>
|
||||||
|
@@ -2,22 +2,87 @@
|
|||||||
<div class="thing-album-detail">
|
<div class="thing-album-detail">
|
||||||
<div class="thing-album-detail-header">
|
<div class="thing-album-detail-header">
|
||||||
<div class="thing-detail-content-nav">
|
<div class="thing-detail-content-nav">
|
||||||
<AButton size="large" type="text" class="thing-detail-content-nav-title">人物</AButton>
|
<AButton size="large" type="text" class="thing-detail-content-nav-title" @click="goBack">人物</AButton>
|
||||||
<span class="thing-detail-content-nav-separator"> > </span>
|
<span class="thing-detail-content-nav-separator"> > </span>
|
||||||
<span class="thing-detail-content-nav-name">人物</span>
|
<span class="thing-detail-content-nav-name">人物</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<ImageToolbar :selected="selected"/>
|
||||||
<div class="thing-album-detail-info">
|
<div class="thing-album-detail-info">
|
||||||
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
<span style="font-size: 14px;color: #999999">共12张照片</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="thing-album-detail-list">
|
<div class="thing-album-detail-list">
|
||||||
|
<div style="width:100%;height:100%;">
|
||||||
|
<div v-for="(itemList, index) in albumList" :key="index">
|
||||||
|
<span style="margin-left: 10px;font-size: 13px">{{ itemList.date }}</span>
|
||||||
|
<AImagePreviewGroup>
|
||||||
|
<Vue3JustifiedLayout v-model:list="itemList.list" :options="options">
|
||||||
|
<template #default="{ item }">
|
||||||
|
<CheckCard :key="index"
|
||||||
|
class="photo-item"
|
||||||
|
margin="0"
|
||||||
|
border-radius="0"
|
||||||
|
v-model="selected"
|
||||||
|
:showHoverCircle="true"
|
||||||
|
:iconSize="20"
|
||||||
|
:showSelectedEffect="true"
|
||||||
|
:value="item.id">
|
||||||
|
<AImage :src="item.thumbnail"
|
||||||
|
:alt="item.file_name"
|
||||||
|
:key="index"
|
||||||
|
:height="200"
|
||||||
|
:previewMask="false"
|
||||||
|
:preview="{
|
||||||
|
src: item.url,
|
||||||
|
}"
|
||||||
|
loading="lazy"/>
|
||||||
|
</CheckCard>
|
||||||
|
</template>
|
||||||
|
</Vue3JustifiedLayout>
|
||||||
|
</AImagePreviewGroup>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import Vue3JustifiedLayout from "vue3-justified-layout";
|
||||||
|
import 'vue3-justified-layout/dist/style.css';
|
||||||
|
import {queryThingDetailListApi} from "@/api/storage";
|
||||||
|
import ImageToolbar from "@/views/Photograph/ImageToolbar/ImageToolbar.vue";
|
||||||
|
|
||||||
|
|
||||||
|
const selected = ref<(string | number)[]>([]);
|
||||||
|
const albumList = ref<any[]>([]);
|
||||||
|
|
||||||
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
const options = reactive({
|
||||||
|
targetRowHeight: 200 // 高度
|
||||||
|
});
|
||||||
|
|
||||||
|
async function getImageList(tag_name: string) {
|
||||||
|
const res: any = await queryThingDetailListApi(tag_name, "ali", "schisandra-album");
|
||||||
|
if (res && res.code === 200) {
|
||||||
|
albumList.value = res.data.records;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const idParam = route.params.id;
|
||||||
|
const tag_name = Array.isArray(idParam) ? idParam[0] : idParam;
|
||||||
|
getImageList(tag_name);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回上一页
|
||||||
|
*/
|
||||||
|
function goBack(): void {
|
||||||
|
router.go(-1);
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.thing-album-detail {
|
.thing-album-detail {
|
||||||
@@ -75,7 +140,7 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
margin-left: 15px;
|
margin-left: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
}
|
}
|
||||||
@@ -83,8 +148,7 @@
|
|||||||
.thing-album-detail-list {
|
.thing-album-detail-list {
|
||||||
width: 99%;
|
width: 99%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin-left: 5px;
|
//margin-left: 5px;
|
||||||
background: #e2e2e2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
创建相册
|
创建相册
|
||||||
</AButton>
|
</AButton>
|
||||||
</div>
|
</div>
|
||||||
<image-toolbar :selected="selected" />
|
<image-toolbar :selected="selected"/>
|
||||||
<div class="photo-list">
|
<div class="photo-list">
|
||||||
<ATabs size="small" :tabBarGutter="50" type="line" tabPosition="top" :tabBarStyle="{position:'unset'}"
|
<ATabs size="small" :tabBarGutter="50" type="line" tabPosition="top" :tabBarStyle="{position:'unset'}"
|
||||||
style="width: 99%;">
|
style="width: 99%;">
|
||||||
@@ -37,11 +37,14 @@
|
|||||||
:iconSize="20"
|
:iconSize="20"
|
||||||
:showSelectedEffect="true"
|
:showSelectedEffect="true"
|
||||||
:value="item.id">
|
:value="item.id">
|
||||||
<AImage :src="item.url"
|
<AImage :src="item.thumbnail"
|
||||||
:alt="item.file_name"
|
:alt="item.file_name"
|
||||||
:key="index"
|
:key="index"
|
||||||
style="height: 200px"
|
:height="200"
|
||||||
:previewMask="false"
|
:previewMask="false"
|
||||||
|
:preview="{
|
||||||
|
src: item.url,
|
||||||
|
}"
|
||||||
loading="lazy"/>
|
loading="lazy"/>
|
||||||
</CheckCard>
|
</CheckCard>
|
||||||
</template>
|
</template>
|
||||||
@@ -73,7 +76,7 @@ import Vue3JustifiedLayout from "vue3-justified-layout";
|
|||||||
import 'vue3-justified-layout/dist/style.css';
|
import 'vue3-justified-layout/dist/style.css';
|
||||||
import ImageUpload from "@/views/Photograph/ImageUpload/ImageUpload.vue";
|
import ImageUpload from "@/views/Photograph/ImageUpload/ImageUpload.vue";
|
||||||
import useStore from "@/store";
|
import useStore from "@/store";
|
||||||
import {queryAllImagesApi} from "@/api/storage";
|
import {getSingleImageApi, queryAllImagesApi} from "@/api/storage";
|
||||||
import ImageToolbar from "@/views/Photograph/ImageToolbar/ImageToolbar.vue";
|
import ImageToolbar from "@/views/Photograph/ImageToolbar/ImageToolbar.vue";
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +90,9 @@ const options = reactive({
|
|||||||
|
|
||||||
const images = ref<any[]>([]);
|
const images = ref<any[]>([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有图片
|
||||||
|
*/
|
||||||
async function getAllImages() {
|
async function getAllImages() {
|
||||||
const res: any = await queryAllImagesApi("image", false, "ali", "schisandra-album");
|
const res: any = await queryAllImagesApi("image", false, "ali", "schisandra-album");
|
||||||
if (res && res.code === 200) {
|
if (res && res.code === 200) {
|
||||||
@@ -95,6 +100,30 @@ async function getAllImages() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const previewUrl = ref<string>("");
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 获取单张图片
|
||||||
|
// * @param id
|
||||||
|
// */
|
||||||
|
// async function getSingleImage(id: number) {
|
||||||
|
// previewUrl.value = "";
|
||||||
|
// const res: any = await getSingleImageApi(id);
|
||||||
|
// if (res && res.code === 200) {
|
||||||
|
// previewUrl.value = res.data;
|
||||||
|
// setVisible(true);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// previewUrl.value = "data:image/png;base64,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";
|
||||||
|
// setVisible(true);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// const visible = ref<boolean>(false);
|
||||||
|
//
|
||||||
|
// const setVisible = (value): void => {
|
||||||
|
// visible.value = value;
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getAllImages();
|
getAllImages();
|
||||||
|
@@ -62,6 +62,7 @@ import imageCompression from "browser-image-compression";
|
|||||||
import exifr from 'exifr';
|
import exifr from 'exifr';
|
||||||
import isScreenshot from "@/utils/imageUtils/isScreenshot.ts";
|
import isScreenshot from "@/utils/imageUtils/isScreenshot.ts";
|
||||||
import {getCategoryByLabel} from "@/constant/coco_ssd_label_category.ts";
|
import {getCategoryByLabel} from "@/constant/coco_ssd_label_category.ts";
|
||||||
|
import {generateThumbnail} from "@/utils/imageUtils/generateThumb.ts";
|
||||||
|
|
||||||
const predicting = ref<boolean>(false);
|
const predicting = ref<boolean>(false);
|
||||||
const progressPercent = ref<number>(0);
|
const progressPercent = ref<number>(0);
|
||||||
@@ -145,7 +146,7 @@ async function beforeUpload(file: File, fileList: File[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 提取 EXIF 数据
|
// 提取 EXIF 数据
|
||||||
const gpsData = await extractGPSExifData(file);
|
const gpsData: any = await extractGPSExifData(file);
|
||||||
if (gpsData) {
|
if (gpsData) {
|
||||||
upload.predictResult.longitude = gpsData.longitude;
|
upload.predictResult.longitude = gpsData.longitude;
|
||||||
upload.predictResult.latitude = gpsData.latitude;
|
upload.predictResult.latitude = gpsData.latitude;
|
||||||
@@ -210,12 +211,21 @@ const {uploading, send: submitFile, abort} = useRequest(uploadFile, {
|
|||||||
* @param file
|
* @param file
|
||||||
*/
|
*/
|
||||||
async function customUploadRequest(file: any) {
|
async function customUploadRequest(file: any) {
|
||||||
|
const compressedFile = await imageCompression(file.file, options);
|
||||||
|
// 生成缩略图
|
||||||
|
const {binaryData, width, height, size} = await generateThumbnail(compressedFile);
|
||||||
|
upload.predictResult.thumb_w = width;
|
||||||
|
upload.predictResult.thumb_h = height;
|
||||||
|
upload.predictResult.thumb_size = size;
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append("file", file.file);
|
formData.append("file", file.file);
|
||||||
|
if (binaryData) {
|
||||||
|
formData.append("thumbnail", binaryData);
|
||||||
|
}
|
||||||
formData.append("data", JSON.stringify({
|
formData.append("data", JSON.stringify({
|
||||||
provider: 'ali',
|
provider: 'ali',
|
||||||
bucket: 'schisandra',
|
bucket: 'schisandra-album',
|
||||||
fileType: file.file.type,
|
fileType: file.file.type,
|
||||||
...upload.predictResult,
|
...upload.predictResult,
|
||||||
}));
|
}));
|
||||||
@@ -276,14 +286,24 @@ async function extractGPSExifData(file) {
|
|||||||
if (!supportedFormats.includes(file.type)) {
|
if (!supportedFormats.includes(file.type)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const options: any = {
|
||||||
|
ifd0: false,
|
||||||
|
exif: false,
|
||||||
|
gps: ['GPSLatitudeRef', 'GPSLatitude', 0x0003, 0x0004],
|
||||||
|
interop: false,
|
||||||
|
ifd1: false // thumbnail
|
||||||
|
};
|
||||||
|
|
||||||
// 提取GPS EXIF 数据
|
// 提取GPS EXIF 数据
|
||||||
let {latitude, longitude} = await exifr.gps(file);
|
const gpsData = await exifr.parse(file, options);
|
||||||
if (latitude && longitude) {
|
if (!gpsData) {
|
||||||
return {latitude, longitude};
|
|
||||||
} else {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
const {latitude, longitude} = gpsData;
|
||||||
|
if (latitude && longitude) {
|
||||||
|
return {latitude, longitude};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
Reference in New Issue
Block a user