gaoluyang
2026-06-24 bfdc0e0e6d5e47aa501f9b6fadd143d9c97cf00a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
<script setup lang="ts">
import type { MagicCubeProperty } from './config';
 
import { computed } from 'vue';
 
import { IconifyIcon } from '../../../../../../../../packages/icons/src';
 
import { Image } from 'ant-design-vue';
 
/** 广告魔方 */
defineOptions({ name: 'MagicCube' });
 
const props = defineProps<{ property: MagicCubeProperty }>();
 
const CUBE_SIZE = 93.75; // 一个方块的大小
 
/**
 * 计算方块的行数
 * 行数用于计算魔方的总体高度,存在以下情况:
 * 1. 没有数据时,默认就只显示一行的高度
 * 2. 底部的空白不算高度,例如只有第一行有数据,那么就只显示一行的高度
 * 3. 顶部及中间的空白算高度,例如一共有四行,只有最后一行有数据,那么也显示四行的高度
 */
const rowCount = computed(() => {
  let count = 0;
  if (props.property.list.length > 0) {
    // 最大行号
    count = Math.max(
      ...props.property.list.map((item) => item.top + item.height),
    );
  }
  // 保证至少有一行
  return count === 0 ? 1 : count;
});
</script>
 
<template>
  <div
    class="relative"
    :style="{
      height: `${rowCount * CUBE_SIZE}px`,
      width: `${4 * CUBE_SIZE}px`,
      padding: `${property.space}px`,
    }"
  >
    <div
      v-for="(item, index) in property.list"
      :key="index"
      class="absolute"
      :style="{
        width: `${item.width * CUBE_SIZE - property.space}px`,
        height: `${item.height * CUBE_SIZE - property.space}px`,
        top: `${item.top * CUBE_SIZE}px`,
        left: `${item.left * CUBE_SIZE}px`,
      }"
    >
      <Image
        class="h-full w-full object-cover"
        :src="item.imgUrl"
        :preview="false"
        :style="{
          borderTopLeftRadius: `${property.borderRadiusTop}px`,
          borderTopRightRadius: `${property.borderRadiusTop}px`,
          borderBottomLeftRadius: `${property.borderRadiusBottom}px`,
          borderBottomRightRadius: `${property.borderRadiusBottom}px`,
        }"
      >
        <template #error>
          <div class="image-slot">
            <div
              class="flex items-center justify-center"
              :style="{
                width: `${item.width * CUBE_SIZE}px`,
                height: `${item.height * CUBE_SIZE}px`,
              }"
            >
              <IconifyIcon icon="ep-picture" color="gray" :size="CUBE_SIZE" />
            </div>
          </div>
        </template>
      </Image>
    </div>
  </div>
</template>