Commit 4bab7c9a authored by shirlyn.guo's avatar shirlyn.guo 🤡

chore: 推荐模板布局优化

parent 4e2512d2
<script setup lang="ts"> <script setup lang="ts">
import { computed, onMounted, ref, watch, useTemplateRef } from 'vue' import { computed, ref, watch, useTemplateRef } from 'vue'
import TemplatePreviewModal from './template-preview-modal.vue' import TemplatePreviewModal from './template-preview-modal.vue'
import { useScroll } from '@vueuse/core' import { useScroll } from '@vueuse/core'
import { DigitalTemplate, TemplateType } from '@/store/types/template' import { DigitalTemplate, TemplateType } from '@/store/types/template'
...@@ -21,16 +21,13 @@ const previewModalVisible = ref(false) ...@@ -21,16 +21,13 @@ const previewModalVisible = ref(false)
const selectedTemplate = ref<DigitalTemplate>({} as DigitalTemplate) const selectedTemplate = ref<DigitalTemplate>({} as DigitalTemplate)
const checkedClassifyValue = ref('') const checkedClassifyValue = ref('')
const templateList = ref<(DigitalTemplate & { position?: { top: number; left: number } })[]>([]) const templateColumnMap = ref(createDefaultDigitalTemplate())
const alreadyCountPositionsList: { id: number; top: number; left: number; height: number; columnIndex: number }[] = []
const pagingInfo = ref({ const pagingInfo = ref({
pageNo: 1, pageNo: 1,
totalPages: 1, totalPages: 1,
pageSize: 30, pageSize: 30,
totalRows: 2, totalRows: 2,
}) })
const columnHeights = ref<number[]>([])
const waterfallHeight = ref(900) const waterfallHeight = ref(900)
const templateClassifyIsLoading = ref(true) const templateClassifyIsLoading = ref(true)
const templateBottomIsLoading = ref(false) const templateBottomIsLoading = ref(false)
...@@ -48,12 +45,9 @@ const templateClassify = [ ...@@ -48,12 +45,9 @@ const templateClassify = [
watch(checkedClassifyValue, () => { watch(checkedClassifyValue, () => {
templateClassifyIsLoading.value = true templateClassifyIsLoading.value = true
templateList.value = [] templateColumnMapReset()
pagingInfo.value.pageNo = 1 pagingInfo.value.pageNo = 1
alreadyCountPositionsList.length = 0 getTemplateList()
columnHeights.value = Array(6).fill(0)
getTemplateList(true)
}) })
watch( watch(
...@@ -68,37 +62,32 @@ watch( ...@@ -68,37 +62,32 @@ watch(
} }
}, },
) )
;(function () {
getTemplateList()
})()
onMounted(() => { function createDefaultDigitalTemplate(): { height: number; list: DigitalTemplate[] }[] {
getTemplateList(true) return Array.from({ length: 6 }, () => ({
columnHeights.value = Array(6).fill(0) height: 0,
}) list: [],
}))
}
async function getTemplateList(refresh = false) { function getTemplateList() {
if (templateBottomIsLoading.value) { if (templateBottomIsLoading.value && templateClassifyIsLoading.value) return
if (templateClassifyIsLoading.value) return
}
fetchDigitalHumanTemplateStatusList<DigitalTemplate[]>(checkedClassifyValue.value, pagingInfo.value) fetchDigitalHumanTemplateStatusList<DigitalTemplate[]>(checkedClassifyValue.value, pagingInfo.value)
.then(async (res) => { .then(async (res) => {
if (res.code !== 0) return if (res.code !== 0) return
templateList.value = refresh ? res.data : [...templateList.value, ...res.data]
templateClassifyIsLoading.value = false templateClassifyIsLoading.value = false
const newTemplateList = res.data
const newTemplateListPositions = await calculatePositions(newTemplateList, alreadyCountPositionsList)
templateList.value = templateList.value.map((template) => { res.data.forEach((item) => {
const itemWithNoPosition = newTemplateList.find((item) => item.id === template.id) templateItemInsertColumn(item)
if (itemWithNoPosition) {
return {
...template,
position: newTemplateListPositions[newTemplateList.indexOf(itemWithNoPosition)],
}
}
return template
}) })
const maxHeight = Math.max(...templateColumnMap.value.map((column) => column.height))
waterfallHeight.value = maxHeight + 20
pagingInfo.value = res.pagingInfo as PagingInfo pagingInfo.value = res.pagingInfo as PagingInfo
}) })
.finally(() => { .finally(() => {
...@@ -106,75 +95,19 @@ async function getTemplateList(refresh = false) { ...@@ -106,75 +95,19 @@ async function getTemplateList(refresh = false) {
}) })
} }
async function calculatePositions( function templateItemInsertColumn(item: DigitalTemplate) {
templates: any[], if (!item.videoParams) return
alreadyPositionsList: { id: number; top: number; left: number; height: number }[],
) {
const columnWidths = 170
const columnHeights = Array(6).fill(0)
const positions: { id: number; top: number; left: number; height: number; columnIndex: number }[] = []
const imgHeights = await Promise.all(
templates.map(async (template) => ({
id: template.id,
imgHeight: await calculateImageHeight(template),
})),
)
alreadyPositionsList.forEach((pos) => {
const columnIndex = Math.floor(pos.left / columnWidths)
columnHeights[columnIndex] = Math.max(columnHeights[columnIndex], pos.top + 20 + pos.height)
})
imgHeights.forEach(({ id, imgHeight }) => {
const minColumnIndex = getMinColumnHeight(columnHeights)
const itemTop = columnHeights[minColumnIndex]
const itemLeft = minColumnIndex * columnWidths + minColumnIndex * 20
columnHeights[minColumnIndex] += imgHeight + 20 const itemHeight = (item.videoParams.height / item.videoParams.width) * 170
waterfallHeight.value = Math.max(...columnHeights) const columnHeights = templateColumnMap.value.map((column) => column.height)
positions.push({ id, top: itemTop, left: itemLeft, height: imgHeight, columnIndex: minColumnIndex }) const minColumnIndex = columnHeights.indexOf(Math.min(...columnHeights))
})
alreadyCountPositionsList.push(...positions)
const columnMap = new Map<number, { id: number; top: number; left: number; height: number; totalValue: number }[]>()
alreadyCountPositionsList.forEach(({ id, top, left, height, columnIndex }) => { templateColumnMap.value[minColumnIndex].list.push(item)
if (!columnMap.has(columnIndex)) { templateColumnMap.value[minColumnIndex].height += itemHeight + 20
columnMap.set(columnIndex, [])
}
columnMap.get(columnIndex)?.push({ id, top, left, height, totalValue: top + height })
})
alreadyCountPositionsList.length = 0
columnMap.forEach((items, columnIndex) => {
const maxItem = items.reduce((prev, current) => (prev.totalValue > current.totalValue ? prev : current))
alreadyCountPositionsList.push({
id: maxItem.id,
top: maxItem.top,
left: maxItem.left,
height: maxItem.height,
columnIndex,
})
})
return positions
}
function calculateImageHeight(template: { videoParams: { width: number; height: number } }): Promise<number> {
return new Promise((resolve) => {
const renderWidth = 170
const renderHeight = (template.videoParams.height / template.videoParams.width) * renderWidth
resolve(renderHeight)
})
} }
function getMinColumnHeight(arr: number[]) { function templateColumnMapReset() {
let min = Math.min(...arr) templateColumnMap.value = createDefaultDigitalTemplate()
return arr.indexOf(min)
} }
function handleOpenPreviewModal(template: DigitalTemplate) { function handleOpenPreviewModal(template: DigitalTemplate) {
...@@ -215,14 +148,12 @@ function handleToCreation(template: DigitalTemplate) { ...@@ -215,14 +148,12 @@ function handleToCreation(template: DigitalTemplate) {
> >
<div <div
v-show="!templateClassifyIsLoading" v-show="!templateClassifyIsLoading"
class="page-main relative h-auto min-h-[900px] w-full" class="page-main relative flex h-auto min-h-[900px] w-full justify-between"
:style="{ height: waterfallHeight + 'px' }" :style="{ height: waterfallHeight + 40 + 'px' }"
>
<div v-for="item in templateList" :key="item.id">
<div
v-if="item.position"
:style="{ position: 'absolute', top: item.position!.top + 'px', left: item.position!.left + 'px' }"
> >
<div v-for="(column, index) in templateColumnMap" :key="index">
<div v-for="item in column.list" :key="item.id">
<div>
<n-card class="mb-[20px] box-content w-[170px] overflow-hidden"> <n-card class="mb-[20px] box-content w-[170px] overflow-hidden">
<template #cover> <template #cover>
<div class="relative flex h-auto w-[170px] items-center justify-center overflow-hidden bg-[#f0f0f0]"> <div class="relative flex h-auto w-[170px] items-center justify-center overflow-hidden bg-[#f0f0f0]">
...@@ -251,12 +182,13 @@ function handleToCreation(template: DigitalTemplate) { ...@@ -251,12 +182,13 @@ function handleToCreation(template: DigitalTemplate) {
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="flex justify-center"> <div class="flex justify-center">
<n-spin v-show="templateClassifyIsLoading" size="large" /> <n-spin v-show="templateClassifyIsLoading" size="large" />
</div> </div>
<div <div
v-show="pagingInfo.pageNo === pagingInfo.totalPages || pagingInfo.totalPages === 0" v-show="pagingInfo.pageNo === pagingInfo.totalPages || pagingInfo.totalPages === 0"
class="mb-[50px] mt-[20px] flex justify-center text-center text-[14px] text-[#a9b4cc]" class="mb-[50px] mt-[30px] flex justify-center text-center text-[14px] text-[#a9b4cc]"
> >
<div class="relative top-[10px] h-[1px] w-[14px] bg-[#a9b4cc]"></div> <div class="relative top-[10px] h-[1px] w-[14px] bg-[#a9b4cc]"></div>
<div class="mb-[8px] w-[80px]">已經到底啦</div> <div class="mb-[8px] w-[80px]">已經到底啦</div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment