You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ocr-web/src/views/home/content/Content.vue

434 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts" setup>
import { getPictureList, oneClickCheck } from '@/api/home/main'
import img1 from '@/assets/images/1.jpg'
import img2 from '@/assets/images/2.jpg'
import img3 from '@/assets/images/3.jpg'
import img4 from '@/assets/images/4.jpg'
import img5 from '@/assets/images/5.jpg'
import { timeOptions, viewOptions } from '@/config/home'
import { useWindowSizeFn } from '@/hooks/event/useWindowSizeFn'
import { useConfig } from '@/store/modules/asideConfig'
import { getViewportOffset } from '@/utils/domUtils'
import { randomInt } from '@/utils/index'
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, onBeforeMount, onMounted, onUnmounted, onUpdated, reactive, ref, unref, watch } from 'vue'
import LoginSuccessModal from './modal/LoginSuccessModal.vue'
import PackageSettingsModal from './modal/PackageSettingsModal.vue'
const deviceHeight = ref(600)
let _masonry: null | Masonry = null
let _imagesload: any
const masonryRef = ref<ComponentRef>(null)
const el = ref<HTMLDivElement | null>(null)
const viewMode = ref('masonry')
const pagination = reactive({
pageNo: 1,
pageSize: 30,
})
const configStore = useConfig()
const packageModalRef = ref(null)
const LoginSuccessModalRef = ref(null)
const loading = ref(false)
const message = useMessage()
async function computeListHeight() {
const headEl = document.querySelector('.wrapper-content')!
const { bottomIncludeBody } = getViewportOffset(headEl)
const height = bottomIncludeBody
deviceHeight.value = height - 40 - 16 - 24
}
useWindowSizeFn(computeListHeight)
const listStyle = computed(() => {
return {
height: `${deviceHeight.value}px`,
}
})
const layout = debounce(() => {
if (masonryRef.value == null || el.value == null)
return
if (_masonry !== null)
(_masonry as any).destroy()
_masonry = new Masonry(masonryRef.value as any, {
itemSelector: '.grid-item',
gutter: 18,
columnWidth: 182,
percentPosition: true,
stagger: 10,
})
_imagesload = imagesloaded('.grid-item')
_imagesload.on('always', (instance) => {
console.log('always')
})
_imagesload.on('done', (instance) => {
(_masonry as any).layout()
const scrollHeight = el.value!.scrollHeight
const clientHeight = el.value!.clientHeight
const top = scrollHeight - clientHeight - 20
el.value!.scrollTo({ top, behavior: 'instant' })
loading.value = false
})
_imagesload.on('fail', (instance) => {
message.error('图片错误')
loading.value = false
})
// imagesloaded('.grid-item', () => {
// (_masonry as any).layout()
// const scrollHeight = el.value!.scrollHeight
// const clientHeight = el.value!.clientHeight
// const top = scrollHeight - clientHeight - 20
// el.value!.scrollTo({ top, behavior: 'instant' })
// loading.value = false
// })
}, 300)
let canloadMore = true
useInfiniteScroll(
el as any,
() => {
loadMore()
},
{ distance: 10, canLoadMore: () => canloadMore },
)
onUpdated(() => {
layout()
})
const timeRange = ref('99')
const timeLabel = computed(() => {
const item = timeOptions.find((option) => {
return option.value === timeRange.value
})
return item?.label
})
const viewLabel = computed(() => {
const item = viewOptions.find((option) => {
return option.value === viewMode.value
})
return item?.label
})
const listData = ref<any[]>([])
const urls = [
img1,
img2,
img3,
img4,
img5,
]
function randomUrl() {
const index = randomInt(0, urls.length)
return urls[index]
}
async function featchList() {
loading.value = true
try {
const contentParams = {
search_month: timeRange.value,
search_history: 0,
}
const result = await getPictureList({ ...pagination, ...contentParams })
// TODO测试数据
// result.data = Array.from({ length: 30 })
// result.pageCount = 1
const { data, pageCount } = result
pagination.pageNo += 1
canloadMore = pageCount >= pagination.pageNo
const list = data.map((item) => {
return {
imgUrl: item.imgurl,
upname: item.upname,
ocrPictureclass: item.ocrPictureclass,
uphead: item.uphead,
}
})
return list
}
catch (error) {
return []
}
}
async function loadMore() {
if (loading.value || el.value == null) {
// console.log('图片加载中....')
return
}
const more = await featchList()
listData.value.push(...more)
}
onBeforeMount(async () => {
const list = await featchList()
listData.value = list
})
const gridHeight = computed(() => {
return viewMode.value !== 'masonry' ? '145px' : ''
})
async function oneCheck() {
const modal = packageModalRef.value as any
modal.showModal()
}
async function showLoginSuccessModal(){
const modal = LoginSuccessModalRef.value as any
modal.showModal()
}
async function commitHandler(settingParam) {
const contentParams = {
search_month: timeRange.value,
}
const asideVal = configStore.getAsideValue
const finalParam = { ...contentParams, ...asideVal }
finalParam.buessinessno = settingParam.packagename
finalParam.search_history = settingParam.comparehistory ? 1 : 0
// TODO添加重复标识参数
oneClickCheck(finalParam)
}
onMounted(() => {
emitter.on('filter', refreshHandler)
nextTick(() => {
computeListHeight()
// 登录后展示成功
showLoginSuccessModal()
})
})
onUnmounted(() => {
emitter.off('filter', refreshHandler)
})
watch(timeRange, () => {
refreshHandler()
})
watch(() => configStore.asideValue, (newVal, oldVal) => {
refreshHandler()
}, { deep: true })
async function refreshHandler() {
pagination.pageNo = 1
pagination.pageSize = 30
listData.value.length = 0
loading.value = true
const contentParams = {
search_month: timeRange.value,
search_history: 0,
}
const filterParams = unref(configStore.getAsideValue)
const result = await getPictureList({ ...pagination, ...contentParams, ...filterParams })
const { data, pageCount } = result
pagination.pageNo += 1
canloadMore = pageCount >= pagination.pageNo
const list = data.map((item) => {
return {
imgUrl: item.imgurl,
upname: item.upname,
ocrPictureclass: item.ocrPictureclass,
uphead: item.uphead,
}
})
listData.value = list
}
</script>
<template>
<div class="wrapper">
<div class="wrapper-header">
<div class="wrapper-header-left">
<SvgIcon size="32" name="magnifying" />
<span class="wrapper-header-font">AI一键查重</span>
</div>
<SvgIcon style="cursor: pointer;" size="105" name="yijianchachong" @click="oneCheck" />
</div>
<div class="wrapper-content">
<div class="wrapper-content-form">
<n-popselect v-model:value="timeRange" :options="timeOptions" trigger="click">
<div class="wrapper-content-dropdown">
<span>{{ timeLabel || '请选择' }}</span>
<SvgIcon class="wrapper-content-dropdown-gap" name="arrow-botton" size="14" />
</div>
</n-popselect>
<n-popselect v-model:value="viewMode" :options="viewOptions" trigger="click">
<div class="wrapper-content-dropdown">
<span>{{ viewLabel || '请选择' }}</span>
<SvgIcon class="wrapper-content-dropdown-gap" name="arrow-botton" size="14" />
</div>
</n-popselect>
</div>
<div ref="el" class="scroll" :style="listStyle">
<!-- <n-scrollbar :on-scroll="scrollHandler"> -->
<n-spin :show="loading">
<div ref="masonryRef" class="grid">
<div v-for="(item, index) in listData" :key="index" :style="{ height: gridHeight }" class="grid-item">
<!-- <div :style="{ 'background-color': randomColor(0.2) }" class="wrapper-content-item-img" /> -->
<img
class="wrapper-content-item-img" :class="{ 'wrapper-content-item-img-fit': viewMode !== 'masonry' }"
:src="item.imgUrl"
>
<div class="wrapper-content-item-info">
<div class="wrapper-content-item-info-left">
<n-avatar :src="getImgUrl(item.uphead)" class="wrapper-content-item-info-avatar" round />
<span>{{ item.upname }}</span>
</div>
<div class="wrapper-content-item-info-right">
<span :style="{ marginRight: '5px' }"></span>
<span>{{ item.ocrPictureclass?.classname }}</span>
</div>
</div>
</div>
</div>
</n-spin>
<!-- </n-scrollbar> -->
</div>
</div>
<PackageSettingsModal ref="packageModalRef" @commit="commitHandler" />
<LoginSuccessModal ref="LoginSuccessModalRef" />
</div>
</template>
<style lang="less" scoped>
.wrapper {
display: flex;
flex: 1;
flex-direction: column;
box-sizing: border-box;
margin-left: 16px;
width: 100%;
&-header {
display: flex;
justify-content: space-between;
align-items: center;
background: #FFF;
padding: 0px 15px 0px 15px;
box-sizing: border-box;
height: 64px;
border: 1px solid rgb(239, 239, 245);
border-radius: 3px;
width: 100%;
&-left {
display: flex;
align-items: center;
}
&-font {
font-size: 18px;
font-weight: bold;
color: #333333;
line-height: 25px;
margin-left: 12px;
}
}
&-content {
flex: 1;
padding: 16px 16px 0px 16px;
margin-top: 16px;
background: #FFF;
border-radius: 3px;
border: 1px solid rgb(239, 239, 245);
&-form {
display: flex;
align-items: center;
font-size: 14px;
padding-bottom: 16px;
}
&-item {
&-img {
border-radius: 7px;
display: block;
height: calc(100% - 20px);
}
&-img-fit {
width: 100%;
object-fit: cover;
}
&-info {
display: flex;
justify-content: space-between;
margin-top: 4px;
&-left {
display: flex;
align-items: center;
}
&-right {
display: flex;
align-items: center;
}
&-avatar {
width: 15px;
height: 15px;
margin-right: 5px;
}
}
}
&-dropdown {
display: flex;
flex-direction: row;
align-items: center;
margin-right: 24px;
&-gap {
margin-left: 5px;
}
}
.grid-item {
width: 182px;
border-radius: 7px;
margin-bottom: 20px;
}
.scroll {
overflow-y: scroll;
}
}
}
</style>