AI_Painting_V2.0/src/views/home/display/index.vue

363 lines
8.7 KiB
Vue

<template>
<div id="display" class="content-area">
<RefreshOverlay :visible="refreshing" />
<Canvas v-model:visible="canvasVisible" :image="canvasImage" :reference-images="canvasReferenceImages" :source="canvasSource" :type="props.type" @send="handleCanvasSend" />
<div class="back" @click="handleExit">
<img src="@/assets/display/back.svg" alt="">
<span class="title-text">退出</span>
</div>
<div v-if="props.if" class="btn-container">
<div class="btn">
<img src="@/assets/display/search.svg" alt="">
</div>
<span class="line"></span>
<div class="btn">
<Select v-model="selectedTime" :options="timeOptions" width="auto">
<template #prefix>
<i-ep-Calendar />
</template>
<template #header>
<div class="header">
<el-date-picker
v-model="value1"
type="daterange"
start-placeholder="Start date"
end-placeholder="End date"
:size="size"
/>
</div>
</template>
</Select>
</div>
<span class="line"></span>
<div class="btn">
<Select v-model="selectedFavorite" :options="favoriteOptions" width="auto" >
<template #prefix>
<i-ep-Star />
</template>
</Select>
</div>
</div>
<VirtualScroller
ref="scrollerRef"
v-if="props.if"
:items="list"
key-field="id"
:estimated-height="300"
:buffer-size="3"
direction="reverse"
:bottom-placeholder-height="350"
class="scroller"
@scroll="handleScroll"
@visible-change="handleVisibleChange"
>
<template #default="{ item, index }">
<Set :key="item.id" :item="item" @open-canvas="openCanvas" @delete-success="handleDeleteSuccess" />
</template>
<template #bottom-placeholder>
<div style="height: 350px;"></div>
</template>
</VirtualScroller>
</div>
</template>
<script setup>
import { useDisplayStore, useParamStore, useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
import Set from './components/set.vue'
import RefreshOverlay from './components/RefreshOverlay.vue'
import Select from '@/components/Select/index.vue'
import { VirtualScroller } from '@/components/virtual-scroller'
import Canvas from '@/components/canvas/index.vue'
import { getGenerateHistoryList } from '@/apis/display'
import { useRouter } from 'vue-router'
import { getChargeType } from '@/utils/websocket'
const props = defineProps({
if: {
type: Boolean,
default: false
},
loading: {
type: Boolean,
default: false
},
type: {
type: String,
default: 'painting'
}
})
const useDisplay = useDisplayStore()
const useParams = useParamStore()
const userStore = useUserStore()
const router = useRouter()
const refreshing = ref(false)
const scrollerRef = ref(null)
const isLoadingMoreLocked = ref(false)
const activeTab = ref('all')
const isInitializing = ref(true)
const { canvasVisible, canvasImage, canvasReferenceImages, canvasSource } = storeToRefs(useDisplay)
const chargeType = computed(() => getChargeType(props.type))
// console.log(chargeType.value)
const timeOptions = [
{ label: '全部', value: 'all' },
{ label: '最近一周', value: 'week' },
{ label: '最近一个月', value: 'month' },
{ label: '最近三个月', value: 'quarter' }
]
const favoriteOptions = [
{ label: '全部', value: 'all' },
{ label: '已收藏', value: 'favorite' }
]
const selectedTime = ref('all')
const selectedFavorite = ref('all')
const { tempList, currentPage, hasMoreData, isLoading } = storeToRefs(useDisplay)
const activeFilter = ref('all')
const list = computed(() => {
const data = tempList.value || []
if (activeFilter.value === 'all') {
return data
}
return data.filter((item) => item.type === activeFilter.value)
})
const toggleDisplay = (newValue, oldValue) => {
activeFilter.value = newValue
}
const conversion = (newlist) => {
const temp = newlist.map((item) => {
const files = item.fileUrl ? item.fileUrl.split(',').filter(url => url.trim()) : []
const generateData = JSON.parse(item.result || '{}')
return {
id: item.id,
taskId: item.taskId,
type: props.type,
collection: item.collection,
status: 'success',
generateData: generateData,
time: item.createTime,
files: files,
collectStatus: item.collectStatus || {}
}
})
console.log(temp)
return temp
}
const fetchHistory = async (isLoadMore = false) => {
if (isLoading.value || (!isLoadMore && !hasMoreData.value)) return
isLoading.value = true
try {
const pageToFetch = isLoadMore ? currentPage.value + 1 : 1
const result = await getGenerateHistoryList({
userId: userStore.userInfo.id,
chargeType: chargeType.value,
page: pageToFetch,
size: 10,
sort: 'createTime,desc'
})
const dataList = result.data?.list || result.data || []
if (dataList.length === 0) {
hasMoreData.value = false
if (!isLoadMore) {
refreshing.value = false
isInitializing.value = false
useDisplay.Sender_variant = 'updown'
router.push({ name: 'generate' })
}
return
}
const adaptedList = conversion(dataList)
if (isLoadMore) {
useDisplay.appendHistoryList(adaptedList)
currentPage.value = pageToFetch
} else {
useDisplay.initHistoryList(adaptedList)
currentPage.value = 1
await nextTick()
for (let i = 0; i < 5; i++) {
setTimeout(() => {
if (scrollerRef.value && typeof scrollerRef.value.scrollToBottom === 'function') {
scrollerRef.value.scrollToBottom()
}
}, 100 * i)
}
setTimeout(() => {
if (scrollerRef.value && typeof scrollerRef.value.scrollToBottom === 'function') {
scrollerRef.value.scrollToBottom()
}
setTimeout(() => {
refreshing.value = false
isInitializing.value = false
useDisplay.scrollToBottom()
}, 300)
}, 600)
}
hasMoreData.value = dataList.length === 10
} catch (error) {
console.error('获取历史失败:', error)
ElMessage({
message: '获取历史失败',
type: 'warning'
})
} finally {
isLoading.value = false
}
}
const handleScroll = (scrollInfo) => {
if (isInitializing.value) return
if (!scrollInfo) return
const { isAtPageTop, isAtPageBottom, distanceToPageTop, distanceToPageBottom } = scrollInfo
if (isAtPageTop && !isLoading.value && !isLoadingMoreLocked.value && hasMoreData.value) {
isLoadingMoreLocked.value = true
fetchHistory(true)
setTimeout(() => {
isLoadingMoreLocked.value = false
}, 3000)
}
if (isAtPageBottom) {
useDisplay.Sender_variant = 'updown'
} else if (distanceToPageTop >= 350) {
useDisplay.Sender_variant = 'default'
}
}
const handleVisibleChange = (startIndex, endIndex) => {
}
const handleScrollStart = () => {}
const handleScrollEnd = () => {}
const openCanvas = (data) => {
useDisplay.openCanvas(data)
}
const handleCanvasSend = (data) => {
console.log('Canvas send:', data)
}
const handleExit = () => {
if (window.parent !== window) {
window.parent.postMessage({
action: 'navigateBack',
source: 'display-exit'
}, 'https://sxwz.xueai.art')
} else {
router.go(-1)
}
}
const handleDeleteSuccess = (id) => {
useDisplay.deleteHistoryItem(id)
}
onMounted(() => {
if (!props.loading) return
refreshing.value = true
nextTick(() => {
useDisplay.scrollerRef = scrollerRef.value
useDisplay.resetPagination()
fetchHistory()
})
})
onBeforeUnmount(() => {
useDisplay.resetPagination()
})
</script>
<style lang="less" scoped>
.content-area {
width: 100%;
min-width: 750px;
height: 100%;
overflow-y: auto;
transition: all 0.3s ease;
}
.back{
display: flex;
align-items: center;
gap: 6px;
height: 36px;
padding: 10px;
position: absolute;
left: 30px;
top: 22px;
z-index: 3;
cursor: pointer;
border-radius: 10px;
}
.back:hover{
background-color: #e4e7ed;
}
.btn-container{
display: flex;
align-items: center;
gap: 6px;
height: auto;
padding: 4px;
right: 30px;
top: 22px;
z-index: 3;
border-radius: 10px;
background-color: #FAFBFC;
position: absolute;
.btn{
display: flex;
padding: 5px;
align-items: center;
gap: 5px;
}
.btn-text{
color: #000;
font-family: "Microsoft YaHei";
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px;
text-align: center;
}
.line{
width: 1px;
height: 8px;
background-color: #ccc;
}
}
</style>