diff --git a/README.md b/README.md
index a5746ce..affec36 100644
--- a/README.md
+++ b/README.md
@@ -19,6 +19,8 @@ log-lottery是一个可配置可定制化的抽奖应用,炫酷3D球体,可
> 如果进入网站遇到图片无法显示或有报错的情况,请先到【全局配置】-【界面配置】菜单中点击【重置所有数据】按钮清除数据后进行更新。
+> 不支持内定功能
+
## 要求
使用PC端最新版Chrome或Edge浏览器。
diff --git a/src/hooks/useElement.ts b/src/hooks/useElement.ts
deleted file mode 100644
index 459eb8e..0000000
--- a/src/hooks/useElement.ts
+++ /dev/null
@@ -1,100 +0,0 @@
-import type { IPersonConfig } from '@/types/storeType'
-import { rgba } from '@/utils/color'
-
-export function useElementStyle(element: any, person: IPersonConfig, index: number, patternList: number[], patternColor: string, cardColor: string, cardSize: { width: number, height: number }, textSize: number, mod: 'default' | 'lucky' | 'sphere' = 'default', type: 'add' | 'change' = 'add') {
- if (patternList.includes(index + 1) && mod === 'default') {
- element.style.backgroundColor = rgba(patternColor, Math.random() * 0.2 + 0.8)
- }
- else if (mod === 'sphere' || mod === 'default') {
- element.style.backgroundColor = rgba(cardColor, Math.random() * 0.5 + 0.25)
- }
- else if (mod === 'lucky') {
- element.style.backgroundColor = rgba(cardColor, 0.8)
- }
- element.style.border = `1px solid ${rgba(cardColor, 0.25)}`
- element.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
- element.style.width = `${cardSize.width}px`
- element.style.height = `${cardSize.height}px`
- if (mod === 'lucky') {
- element.className = 'lucky-element-card'
- }
- else {
- element.className = 'element-card'
- }
- if (type === 'add') {
- element.addEventListener('mouseenter', (ev: MouseEvent) => {
- const target = ev.target as HTMLElement
- target.style.border = `1px solid ${rgba(cardColor, 0.75)}`
- target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.75)}`
- })
- element.addEventListener('mouseleave', (ev: MouseEvent) => {
- const target = ev.target as HTMLElement
- target.style.border = `1px solid ${rgba(cardColor, 0.25)}`
- target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
- })
- }
- element.children[0].style.fontSize = `${textSize * 0.5}px`
- if (person.uid) {
- element.children[0].textContent = person.uid
- }
-
- element.children[1].style.fontSize = `${textSize}px`
- element.children[1].style.lineHeight = `${textSize * 3}px`
- element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
- if (person.name) {
- element.children[1].textContent = person.name
- }
- // element.children[2].style.fontSize = `${textSize * 0.5}px`
- // if (person.department || person.identity) {
- // element.children[2].innerHTML = `${person.department ? person.department : ''}
${person.identity ? person.identity : ''}`
- // }
-
- element.children[2].style.fontSize = `${textSize * 0.5}px`
- // 设置部门和身份的默认值
- element.children[2].innerHTML = ''
- if (person.department || person.identity) {
- element.children[2].innerHTML = `${person.department ? person.department : ''}
${person.identity ? person.identity : ''}`
- }
- element.children[3].src = person.avatar
- return element
-}
-
-/**
- * @description 设置抽中卡片的位置
- * 最少一个,最大十个
- */
-// TODO:不超过5个时:单行排列;超过5个时,6:上3下3;7:上3下4;8:上3下5;9:上4下5;10:上5下5
-export function useElementPosition(element: any, count: number, totalCount: number, cardSize: { width: number, height: number }, windowSize: { width: number, height: number }, cardIndex: number) {
- let xTable = 0
- let yTable = 0
- const centerPosition = {
- x: 0,
- y: windowSize.height / 2 - cardSize.height * 0.9,
- }
- // 有一行为偶数的特殊数量
- const specialPosition = [2, 4, 7, 9]
- // 不包含特殊值的 和 分两行中第一行为奇数值的
- if (!specialPosition.includes(totalCount) || (totalCount > 5 && cardIndex < 5)) {
- const index = cardIndex % 5
- if (index === 0) {
- xTable = centerPosition.x
- yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
- }
- else {
- xTable = index % 2 === 0 ? Math.ceil(index / 2) * (cardSize.width + 100) : -Math.ceil(index / 2) * (cardSize.width + 100)
- yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
- }
- }
- else {
- const index = cardIndex % 5
- if (index === 0) {
- xTable = centerPosition.x + (cardSize.width + 100) / 2
- yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
- }
- else {
- xTable = index % 2 === 0 ? Math.ceil(index / 2) * (cardSize.width + 100) + (cardSize.width + 100) / 2 : -(Math.ceil(index / 2) * (cardSize.width + 100)) + (cardSize.width + 100) / 2
- yTable = centerPosition.y - Math.floor(cardIndex / 5) * (cardSize.height + 60)
- }
- }
- return { xTable, yTable }
-}
diff --git a/src/hooks/useElement/index.ts b/src/hooks/useElement/index.ts
new file mode 100644
index 0000000..043a356
--- /dev/null
+++ b/src/hooks/useElement/index.ts
@@ -0,0 +1,323 @@
+import type { IPersonConfig } from '@/types/storeType'
+import { rgba } from '@/utils/color'
+
+interface IUseElementStyle {
+ element: any
+ person: IPersonConfig
+ index: number
+ patternList: number[]
+ patternColor: string
+ cardColor: string
+ cardSize: { width: number, height: number }
+ scale: number
+ textSize: number
+ mod: 'default' | 'lucky' | 'sphere'
+ type?: 'add' | 'change'
+
+}
+export function useElementStyle(props: IUseElementStyle) {
+ const { element, person, index, patternList, patternColor, cardColor, cardSize, scale, textSize, mod, type } = props
+ if (patternList.includes(index + 1) && mod === 'default') {
+ element.style.backgroundColor = rgba(patternColor, Math.random() * 0.2 + 0.8)
+ }
+ else if (mod === 'sphere' || mod === 'default') {
+ element.style.backgroundColor = rgba(cardColor, Math.random() * 0.5 + 0.25)
+ }
+ else if (mod === 'lucky') {
+ element.style.backgroundColor = rgba(cardColor, 0.8)
+ }
+ element.style.border = `1px solid ${rgba(cardColor, 0.25)}`
+ element.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
+ element.style.width = `${cardSize.width * scale}px`
+ element.style.height = `${cardSize.height * scale}px`
+ if (mod === 'lucky') {
+ element.className = 'lucky-element-card'
+ }
+ else {
+ element.className = 'element-card'
+ }
+ if (type === 'add') {
+ element.addEventListener('mouseenter', (ev: MouseEvent) => {
+ const target = ev.target as HTMLElement
+ target.style.border = `1px solid ${rgba(cardColor, 0.75)}`
+ target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.75)}`
+ })
+ element.addEventListener('mouseleave', (ev: MouseEvent) => {
+ const target = ev.target as HTMLElement
+ target.style.border = `1px solid ${rgba(cardColor, 0.25)}`
+ target.style.boxShadow = `0 0 12px ${rgba(cardColor, 0.5)}`
+ })
+ }
+ element.children[0].style.fontSize = `${textSize * scale * 0.5}px`
+ if (person.uid) {
+ element.children[0].textContent = person.uid
+ }
+
+ element.children[1].style.fontSize = `${textSize * scale}px`
+ element.children[1].style.lineHeight = `${textSize * scale * 3}px`
+ element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
+ if (person.name) {
+ element.children[1].textContent = person.name
+ }
+
+ element.children[2].style.fontSize = `${textSize * scale * 0.5}px`
+ // 设置部门和身份的默认值
+ element.children[2].innerHTML = ''
+ if (person.department || person.identity) {
+ element.children[2].innerHTML = `${person.department ? person.department : ''}
${person.identity ? person.identity : ''}`
+ }
+ element.children[3].src = person.avatar
+ return element
+}
+interface CardRule {
+ [key: number]: {
+ maxLine: number
+ scale: number
+ rule: number[]
+ length: number
+ }
+}
+const cardRule: CardRule = {
+ 1: {
+ maxLine: 5,
+ scale: 2,
+ rule: [1],
+ length: 1,
+ },
+ 2: {
+ maxLine: 5,
+ scale: 2,
+ rule: [2],
+ length: 1,
+ },
+ 3: {
+ maxLine: 5,
+ scale: 2,
+ rule: [3],
+ length: 1,
+ },
+ 4: {
+ maxLine: 5,
+ scale: 2,
+ rule: [4],
+ length: 1,
+ },
+ 5: {
+ maxLine: 5,
+ scale: 2,
+ rule: [5],
+ length: 1,
+ },
+ 6: {
+ maxLine: 3,
+ scale: 2,
+ rule: [3, 3],
+ length: 2,
+ },
+ 7: {
+ maxLine: 4,
+ scale: 2,
+ rule: [3, 4],
+ length: 2,
+ },
+ 8: {
+ maxLine: 5,
+ scale: 2,
+ rule: [3, 5],
+ length: 2,
+ },
+ 9: {
+ maxLine: 5,
+ scale: 2,
+ rule: [4, 5],
+ length: 2,
+ },
+ 10: {
+ maxLine: 5,
+ scale: 2,
+ rule: [5, 5],
+ length: 2,
+ },
+ 11: {
+ maxLine: 6,
+ scale: 1.8,
+ rule: [5, 6],
+ length: 2,
+ },
+ 12: {
+ maxLine: 6,
+ scale: 1.8,
+ rule: [6, 6],
+ length: 2,
+ },
+ 13: {
+ maxLine: 7,
+ scale: 1.6,
+ rule: [6, 7],
+ length: 2,
+ },
+ 14: {
+ maxLine: 7,
+ scale: 1.6,
+ rule: [7, 7],
+ length: 2,
+ },
+ 15: {
+ maxLine: 8,
+ scale: 1.5,
+ rule: [7, 8],
+ length: 2,
+ },
+ 16: {
+ maxLine: 8,
+ scale: 1.5,
+ rule: [8, 8],
+ length: 2,
+ },
+ 17: {
+ maxLine: 6,
+ scale: 1.8,
+ rule: [5, 6, 6],
+ length: 3,
+ },
+ 18: {
+ maxLine: 6,
+ scale: 1.8,
+ rule: [6, 6, 6],
+ length: 3,
+ },
+ 19: {
+ maxLine: 7,
+ scale: 1.6,
+ rule: [6, 6, 7],
+ length: 3,
+ },
+ 20: {
+ maxLine: 5,
+ scale: 1.6,
+ rule: [6, 7, 7],
+ length: 3,
+ },
+ 21: {
+ maxLine: 7,
+ scale: 1.6,
+ rule: [7, 7, 7],
+ length: 3,
+ },
+ 22: {
+ maxLine: 8,
+ scale: 1.5,
+ rule: [7, 7, 8],
+ length: 3,
+ },
+ 23: {
+ maxLine: 8,
+ scale: 1.5,
+ rule: [7, 8, 8],
+ length: 3,
+ },
+ 24: {
+ maxLine: 8,
+ scale: 1.5,
+ rule: [8, 8, 8],
+ length: 3,
+ },
+ 25: {
+ maxLine: 9,
+ scale: 1.3,
+ rule: [8, 8, 9],
+ length: 3,
+ },
+ 26: {
+ maxLine: 9,
+ scale: 1.3,
+ rule: [8, 9, 9],
+ length: 3,
+ },
+ 27: {
+ maxLine: 9,
+ scale: 1.3,
+ rule: [9, 9, 9],
+ length: 3,
+ },
+ 28: {
+ maxLine: 10,
+ scale: 1.2,
+ rule: [9, 9, 10],
+ length: 3,
+ },
+ 29: {
+ maxLine: 10,
+ scale: 1.2,
+ rule: [9, 10, 10],
+ length: 3,
+ },
+ 30: {
+ maxLine: 10,
+ scale: 1.2,
+ rule: [10, 10, 10],
+ length: 3,
+ },
+}
+/**
+ * @description 设置抽中卡片的位置
+ */
+export function useElementPosition(
+ element: any,
+ count: number,
+ totalCount: number,
+ cardSize: { width: number, height: number },
+ windowSize: { width: number, height: number },
+ cardIndex: number,
+): {
+ xTable: number
+ yTable: number
+ scale: number
+} {
+ let xTable = 0
+ let yTable = 0
+ const centerPosition = {
+ x: 0,
+ y: windowSize.height / 2,
+ }
+ const { scale, rule, length } = cardRule[totalCount]
+ // 计算缩放后的卡片尺寸
+ const scaledCardWidth = cardSize.width * scale
+ const scaledCardHeight = cardSize.height * scale
+ // 计算当前卡片在第几行(从0开始)
+ let currentRow = 0
+ let cardIndexInRow = cardIndex // 当前卡片在其所在行中的索引
+
+ // 根据规则确定卡片在哪一行及行内索引
+ let cumulativeCount = 0
+ for (let i = 0; i < rule.length; i++) {
+ if (cardIndex < cumulativeCount + rule[i]) {
+ currentRow = i
+ cardIndexInRow = cardIndex - cumulativeCount
+ break
+ }
+ cumulativeCount += rule[i]
+ }
+
+ // 计算当前行的卡片数量
+ const cardsInCurrentRow = rule[currentRow]
+
+ // 计算每行的垂直中心位置
+ const verticalSpacing = scaledCardHeight * 1.1 // 垂直间距基于缩放后的高度
+ // 计算整体高度并调整居中
+ const totalHeight = (length - 1) * verticalSpacing + scaledCardHeight // 包含卡片本身的高度
+ const centerYOffset = -totalHeight / 2
+
+ // 修改此处逻辑,确保当length=2时,两行围绕中心点对称分布
+ centerPosition.y = windowSize.height / 2 - totalHeight / 2
+
+ yTable = centerPosition.y + currentRow * verticalSpacing + centerYOffset + scaledCardHeight / 2 // 添加卡片高度的一半作为修正
+ // 计算当前行的水平居中偏移
+ const horizontalSpacing = scaledCardWidth * 1.2 // 水平间距基于缩放后的宽度
+ const rowWidth = (cardsInCurrentRow - 1) * horizontalSpacing
+ const offsetX = -rowWidth / 2 // 行内水平居中
+
+ xTable = centerPosition.x + offsetX + cardIndexInRow * horizontalSpacing
+
+ return { xTable, yTable, scale }
+}
diff --git a/src/style/style.scss b/src/style/style.scss
index 38767df..342e40a 100644
--- a/src/style/style.scss
+++ b/src/style/style.scss
@@ -2,6 +2,7 @@
cursor: default;
text-align: center;
user-select: none;
+
.card-id {
position: absolute;
top: 10px;
@@ -21,7 +22,7 @@
z-index: 2;
}
- .card-avatar-name{
+ .card-avatar-name {
top: auto;
bottom: 0;
left: 0px;
@@ -37,7 +38,7 @@
z-index: 2;
}
- .card-avatar{
+ .card-avatar {
position: absolute;
top: 0;
left: 0;
@@ -52,6 +53,8 @@
.lucky-element-card {
cursor: default;
+ user-select: none;
+
&::before {
background-color: linear-gradient(-45deg, #e81cff 0%, #40c9ff 100%);
border: 1px solid linear-gradient(-45deg, #e81cff 0%, #40c9ff 100%);
@@ -79,7 +82,8 @@
// animation: tracking-in-expand-fwd 0.8s cubic-bezier(0.215, 0.61, 0.355, 1) both;
// animation-delay: 0.6s;
}
- .card-avatar-name{
+
+ .card-avatar-name {
top: auto;
bottom: 0;
left: 0px;
@@ -96,7 +100,7 @@
bottom: 15px;
}
- .card-avatar{
+ .card-avatar {
position: absolute;
top: 0;
left: 0;
@@ -107,4 +111,4 @@
height: 240px !important;
object-fit: cover;
}
-}
+}
\ No newline at end of file
diff --git a/src/views/Config/Person/PersonAll/useViewModel.ts b/src/views/Config/Person/PersonAll/useViewModel.ts
index fefaf77..d4280e0 100644
--- a/src/views/Config/Person/PersonAll/useViewModel.ts
+++ b/src/views/Config/Person/PersonAll/useViewModel.ts
@@ -103,7 +103,7 @@ export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref {
const item = objects.value[cardIndex]
- useElementStyle(item.element, {} as any, i, patternList.value, patternColor.value, cardColor.value, cardSize.value, textSize.value, 'sphere')
+ useElementStyle({
+ element: item.element,
+ person: {} as any,
+ index: i,
+ patternList: patternList.value,
+ patternColor: patternColor.value,
+ cardColor: cardColor.value,
+ cardSize: cardSize.value,
+ scale: 1,
+ textSize: textSize.value,
+ mod: 'sphere',
+ })
})
}
luckyTargets.value = []
@@ -485,7 +508,7 @@ export function useViewModel() {
return
}
- luckyCount.value = 10
+ // luckyCount.value = 10
// 自定义抽奖个数
let leftover = currentPrize.value.count - currentPrize.value.isUsedCount
@@ -498,7 +521,7 @@ export function useViewModel() {
}
}
}
- luckyCount.value = leftover < luckyCount.value ? leftover : luckyCount.value
+ luckyCount.value = leftover
// 重构抽奖函数
luckyTargets.value = getRandomElements(personPool.value, luckyCount.value)
luckyTargets.value.forEach((item) => {
@@ -553,7 +576,14 @@ export function useViewModel() {
luckyCardList.value.push(cardIndex)
const totalLuckyCount = luckyTargets.value.length
const item = objects.value[cardIndex]
- const { xTable, yTable } = useElementPosition(item, rowCount.value, totalLuckyCount, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, windowSize, index)
+ const { xTable, yTable, scale } = useElementPosition(
+ item,
+ rowCount.value,
+ totalLuckyCount,
+ { width: cardSize.value.width, height: cardSize.value.height },
+ windowSize,
+ index,
+ )
new TWEEN.Tween(item.position)
.to({
x: xTable,
@@ -562,7 +592,18 @@ export function useViewModel() {
}, 1200)
.easing(TWEEN.Easing.Exponential.InOut)
.onStart(() => {
- item.element = useElementStyle(item.element, person, cardIndex, patternList.value, patternColor.value, luckyColor.value, { width: cardSize.value.width * 2, height: cardSize.value.height * 2 }, textSize.value * 2, 'lucky')
+ item.element = useElementStyle({
+ element: item.element,
+ person,
+ index: cardIndex,
+ patternList: patternList.value,
+ patternColor: patternColor.value,
+ cardColor: luckyColor.value,
+ cardSize: { width: cardSize.value.width, height: cardSize.value.height },
+ scale,
+ textSize: textSize.value,
+ mod: 'lucky',
+ })
})
.start()
.onComplete(() => {
@@ -691,7 +732,19 @@ export function useViewModel() {
if (!objects.value[cardRandomIndexArr[i]]) {
continue
}
- objects.value[cardRandomIndexArr[i]].element = useElementStyle(objects.value[cardRandomIndexArr[i]].element, allPersonList.value[personRandomIndexArr[i]], cardRandomIndexArr[i], patternList.value, patternColor.value, cardColor.value, { width: cardSize.value.width, height: cardSize.value.height }, textSize.value, mod, 'change')
+ objects.value[cardRandomIndexArr[i]].element = useElementStyle({
+ element: objects.value[cardRandomIndexArr[i]].element,
+ person: allPersonList.value[personRandomIndexArr[i]],
+ index: cardRandomIndexArr[i],
+ patternList: patternList.value,
+ patternColor: patternColor.value,
+ cardColor: cardColor.value,
+ cardSize: { width: cardSize.value.width, height: cardSize.value.height },
+ textSize: textSize.value,
+ scale: 1,
+ mod,
+ type: 'change',
+ })
}
}, 200)
}