|
|
|
|
@ -1,13 +1,4 @@
|
|
|
|
|
<script lang="ts" setup>
|
|
|
|
|
import { useInfiniteScroll } from '@vueuse/core'
|
|
|
|
|
import imagesloaded from 'imagesloaded'
|
|
|
|
|
import { debounce } from 'lodash-es'
|
|
|
|
|
import Masonry from 'masonry-layout'
|
|
|
|
|
import { useMessage } from 'naive-ui'
|
|
|
|
|
import { computed, nextTick, onMounted, onUnmounted, onUpdated, reactive, ref, unref, watch } from 'vue'
|
|
|
|
|
import GeneratePackageModal from './modal/GeneratePackageModal.vue'
|
|
|
|
|
import PackageSettingsModal from './modal/PackageSettingsModal.vue'
|
|
|
|
|
import LoginSuccessModal from './modal/LoginSuccessModal.vue'
|
|
|
|
|
import { getPictureList, oneClickCheck } from '@/api/home/main'
|
|
|
|
|
import avatar from '@/assets/images/avatar.jpg'
|
|
|
|
|
import { timeOptions, viewOptions } from '@/config/home'
|
|
|
|
|
@ -17,6 +8,15 @@ import { getViewportOffset } from '@/utils/domUtils'
|
|
|
|
|
import { hideDownload } from '@/utils/image'
|
|
|
|
|
import emitter from '@/utils/mitt'
|
|
|
|
|
import { getImgUrl } from '@/utils/urlUtils'
|
|
|
|
|
import { useInfiniteScroll } from '@vueuse/core'
|
|
|
|
|
import imagesloaded from 'imagesloaded'
|
|
|
|
|
import { debounce } from 'lodash-es'
|
|
|
|
|
import Masonry from 'masonry-layout'
|
|
|
|
|
import { useMessage } from 'naive-ui'
|
|
|
|
|
import { computed, nextTick, onMounted, onUnmounted, onUpdated, reactive, ref, unref, watch } from 'vue'
|
|
|
|
|
import GeneratePackageModal from './modal/GeneratePackageModal.vue'
|
|
|
|
|
import LoginSuccessModal from './modal/LoginSuccessModal.vue'
|
|
|
|
|
import PackageSettingsModal from './modal/PackageSettingsModal.vue'
|
|
|
|
|
|
|
|
|
|
const deviceHeight = ref(600)
|
|
|
|
|
let _masonry: null | Masonry = null
|
|
|
|
|
@ -141,6 +141,7 @@ async function featchList() {
|
|
|
|
|
ocrPictureclass: item.ocrPictureclass,
|
|
|
|
|
uphead: item.uphead,
|
|
|
|
|
similar: item.similarityscore || 0,
|
|
|
|
|
imgName: item.imgname
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
@ -162,14 +163,14 @@ async function loadMore() {
|
|
|
|
|
|
|
|
|
|
const gridHeight = computed(() => {
|
|
|
|
|
let height = ""
|
|
|
|
|
if(viewMode.value ==='masonry'){
|
|
|
|
|
height =''
|
|
|
|
|
}else if(viewMode.value ==='horizontalVersion'){
|
|
|
|
|
height ='145px'
|
|
|
|
|
}else if(viewMode.value ==='verticalVersion'){
|
|
|
|
|
height ='320px'
|
|
|
|
|
}else if(viewMode.value ==='3:4'){
|
|
|
|
|
height ='240px'
|
|
|
|
|
if (viewMode.value === 'masonry') {
|
|
|
|
|
height = ''
|
|
|
|
|
} else if (viewMode.value === 'horizontalVersion') {
|
|
|
|
|
height = '145px'
|
|
|
|
|
} else if (viewMode.value === 'verticalVersion') {
|
|
|
|
|
height = '320px'
|
|
|
|
|
} else if (viewMode.value === '3:4') {
|
|
|
|
|
height = '240px'
|
|
|
|
|
}
|
|
|
|
|
return height
|
|
|
|
|
})
|
|
|
|
|
@ -264,6 +265,52 @@ function sortHandler() {
|
|
|
|
|
sortBy.value = sortBy.value === 'asc' ? 'desc' : 'asc'
|
|
|
|
|
refreshHandler()
|
|
|
|
|
}
|
|
|
|
|
async function downloadImage(item) {
|
|
|
|
|
if (!item.thumburl) {
|
|
|
|
|
message.error('请输入有效的图片链接地址')
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
// 使用 fetch 发送 GET 请求获取图片
|
|
|
|
|
const response = await fetch(item.thumburl, {
|
|
|
|
|
method: 'GET',
|
|
|
|
|
mode: 'cors', // 确保跨域请求被正确处理
|
|
|
|
|
cache: 'default',
|
|
|
|
|
});
|
|
|
|
|
// 检查响应状态码,确保请求成功
|
|
|
|
|
if (!response.ok) {
|
|
|
|
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 读取 Blob 数据
|
|
|
|
|
const blob = await response.blob();
|
|
|
|
|
|
|
|
|
|
// 创建一个新的a标签
|
|
|
|
|
const link = document.createElement('a');
|
|
|
|
|
link.href = URL.createObjectURL(blob);
|
|
|
|
|
link.download = item.imgName; // 设置下载的文件名
|
|
|
|
|
link.style.display = 'none'; // 隐藏链接
|
|
|
|
|
|
|
|
|
|
// 将链接添加到 DOM 中
|
|
|
|
|
document.body.appendChild(link);
|
|
|
|
|
|
|
|
|
|
// 触发下载
|
|
|
|
|
link.click();
|
|
|
|
|
|
|
|
|
|
// 清理
|
|
|
|
|
URL.revokeObjectURL(link.href);
|
|
|
|
|
document.body.removeChild(link);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('下载图片时发生错误:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previewHandler(index: number,event: MouseEvent) {
|
|
|
|
|
event.stopImmediatePropagation();
|
|
|
|
|
event.stopPropagation();
|
|
|
|
|
if (imageRef.value?.[index] && (imageRef.value[index] as any).src)
|
|
|
|
|
(imageRef.value?.[index] as any).mergedOnClick();
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
@ -307,17 +354,27 @@ function sortHandler() {
|
|
|
|
|
class="wrapper-content-item-img" :class="{ 'wrapper-content-item-img-fit': viewMode !== 'masonry' }"
|
|
|
|
|
:src="item.imgUrl"
|
|
|
|
|
> -->
|
|
|
|
|
<n-image
|
|
|
|
|
class="img" :img-props="{ onClick: hideDownload }"
|
|
|
|
|
:class="{ 'img-fit': viewMode === 'horizontalVersion', 'img-full': viewMode === '3:4'|| viewMode === 'verticalVersion' }" :preview-src="item.imgUrl" :src="item.thumburl"
|
|
|
|
|
/>
|
|
|
|
|
<n-image class="img" :img-props="{ onClick: hideDownload }"
|
|
|
|
|
:class="{ 'img-fit': viewMode === 'horizontalVersion', 'img-full': viewMode === '3:4' || viewMode === 'verticalVersion' }"
|
|
|
|
|
:preview-src="item.imgUrl" :src="item.thumburl" ref="imageRef" />
|
|
|
|
|
<div class="percent">
|
|
|
|
|
<SvgIcon size="42" name="tag" />
|
|
|
|
|
<div class="val">
|
|
|
|
|
{{ `${item.similar}%` }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="glass">
|
|
|
|
|
<SvgIcon size="16" name="download" style="margin-top: -6px;cursor: pointer;"
|
|
|
|
|
@click="downloadImage(item)" />
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="info">
|
|
|
|
|
<div class="footer">
|
|
|
|
|
<div class="img-name">{{ item.imgName }}</div>
|
|
|
|
|
<div class="icon-wrap" @click="previewHandler(index, $event)">
|
|
|
|
|
<SvgIcon size="13" name="magnifying-2" style="cursor: pointer;margin-left: 3px;color:#898481" />
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="left">
|
|
|
|
|
<n-avatar :src="getAvatar(item.uphead)" class="avatar" round />
|
|
|
|
|
<span>{{ item.upname }}</span>
|
|
|
|
|
@ -399,9 +456,11 @@ function sortHandler() {
|
|
|
|
|
width: 100%;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.img-full {
|
|
|
|
|
width: 100%;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
::v-deep(img) {
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
@ -413,6 +472,7 @@ function sortHandler() {
|
|
|
|
|
display: flex;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
margin-top: 4px;
|
|
|
|
|
position: relative;
|
|
|
|
|
|
|
|
|
|
.left {
|
|
|
|
|
display: flex;
|
|
|
|
|
@ -448,34 +508,92 @@ function sortHandler() {
|
|
|
|
|
margin-bottom: 10px;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
position: relative;
|
|
|
|
|
}
|
|
|
|
|
transition: 0.5s;
|
|
|
|
|
|
|
|
|
|
.percent {
|
|
|
|
|
.glass {
|
|
|
|
|
position: absolute;
|
|
|
|
|
display: none !important;
|
|
|
|
|
background-color: #FFF;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
padding: 3px;
|
|
|
|
|
top: 10px;
|
|
|
|
|
right: 10px;
|
|
|
|
|
width: 22px;
|
|
|
|
|
height: 22px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.footer {
|
|
|
|
|
display: none;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 40px;
|
|
|
|
|
position: absolute;
|
|
|
|
|
text-align: center;
|
|
|
|
|
z-index: 3;
|
|
|
|
|
right: 0px;
|
|
|
|
|
top: -6px;
|
|
|
|
|
color: #FFF;
|
|
|
|
|
|
|
|
|
|
.val {
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
|
|
|
|
top: 0;
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
top: -45px;
|
|
|
|
|
justify-content: space-between;
|
|
|
|
|
align-items: center;
|
|
|
|
|
padding: 0 10px;
|
|
|
|
|
background: rgba(0, 0, 0, .35);
|
|
|
|
|
border-radius: 7px;
|
|
|
|
|
.img-name {
|
|
|
|
|
width: 70%;
|
|
|
|
|
color: #FFF;
|
|
|
|
|
/* 设置文本溢出时的样式为省略号 */
|
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
|
/* 隐藏超出容器的文本 */
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
/* 确保文本不换行 */
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.icon-wrap {
|
|
|
|
|
width: 22px;
|
|
|
|
|
height: 22px;
|
|
|
|
|
background-color: #FFF;
|
|
|
|
|
border-radius: 6px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
|
|
|
|
|
|
.percent {
|
|
|
|
|
display: none;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.glass {
|
|
|
|
|
display: block !important;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.info .footer {
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-family: PingFang SC, PingFang SC-Semibold;
|
|
|
|
|
font-weight: Semibold;
|
|
|
|
|
text-align: left;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
line-height: 24px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.percent {
|
|
|
|
|
position: absolute;
|
|
|
|
|
text-align: center;
|
|
|
|
|
z-index: 3;
|
|
|
|
|
right: 0px;
|
|
|
|
|
top: -6px;
|
|
|
|
|
color: #FFF;
|
|
|
|
|
|
|
|
|
|
.val {
|
|
|
|
|
position: absolute;
|
|
|
|
|
left: 0;
|
|
|
|
|
top: 0;
|
|
|
|
|
display: block;
|
|
|
|
|
width: 100%;
|
|
|
|
|
height: 100%;
|
|
|
|
|
display: flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
font-size: 12px;
|
|
|
|
|
font-family: PingFang SC, PingFang SC-Semibold;
|
|
|
|
|
font-weight: Semibold;
|
|
|
|
|
text-align: left;
|
|
|
|
|
color: #ffffff;
|
|
|
|
|
line-height: 24px;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.scroll {
|
|
|
|
|
overflow-y: scroll;
|
|
|
|
|
|