feat: 更换背景图片
This commit is contained in:
@@ -1,37 +1,72 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import Sparticles from 'sparticles';
|
import Sparticles from 'sparticles';
|
||||||
import {ref,onMounted,onUnmounted} from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { useElementSize } from '@vueuse/core';
|
import { useElementSize } from '@vueuse/core';
|
||||||
|
import localforage from 'localforage'
|
||||||
|
const props = defineProps({
|
||||||
|
homeBackground: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
url: ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const imageDbStore = localforage.createInstance({
|
||||||
|
name: 'imgStore'
|
||||||
|
})
|
||||||
|
const imgUrl = ref('')
|
||||||
|
const starRef = ref();
|
||||||
|
|
||||||
const starRef=ref();
|
const { width, height } = useElementSize(starRef);
|
||||||
|
let options = ref({ shape: 'star', parallax: 1.2, rotate: true, twinkle: true, speed: 10, count: 200 });
|
||||||
const { width, height}=useElementSize(starRef);
|
function addSparticles(node: any, width: number, height: number) {
|
||||||
let options = ref({ shape: 'star',parallax:1.2,rotate:true,twinkle:true, speed: 10,count:200 });
|
new Sparticles(node, options.value, width, height);
|
||||||
function addSparticles(node:any,width:number,height:number) {
|
|
||||||
new Sparticles(node, options.value,width,height);
|
|
||||||
}
|
}
|
||||||
// 页面大小改变时
|
// 页面大小改变时
|
||||||
const listenWindowSize=()=>{
|
const listenWindowSize = () => {
|
||||||
window.addEventListener('resize',()=>{
|
window.addEventListener('resize', () => {
|
||||||
if (width.value && height.value) {
|
if (width.value && height.value) {
|
||||||
addSparticles(starRef.value,width.value,height.value);
|
addSparticles(starRef.value, width.value, height.value);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(()=>{
|
const getImageStoreItem = async (item: any): Promise<string> => {
|
||||||
addSparticles(starRef.value,width.value,height.value);
|
let image = ''
|
||||||
|
if (item.url == 'Storage') {
|
||||||
|
const key = item.id;
|
||||||
|
image = await imageDbStore.getItem(key) as string
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
image = item.url
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
getImageStoreItem(props.homeBackground).then((image) => {
|
||||||
|
imgUrl.value = image
|
||||||
|
})
|
||||||
|
addSparticles(starRef.value, width.value, height.value);
|
||||||
listenWindowSize()
|
listenWindowSize()
|
||||||
})
|
})
|
||||||
onUnmounted(()=>{
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize',listenWindowSize)
|
window.removeEventListener('resize', listenWindowSize)
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-screen h-screen overflow-hidden bg-transparent" ref="starRef">
|
<div class="home-background w-screen h-screen overflow-hidden" v-if="homeBackground.url">
|
||||||
|
<img :src="imgUrl" class="w-full h-full object-cover" alt="">
|
||||||
|
</div>
|
||||||
|
<div v-else class="w-screen h-screen overflow-hidden" ref="starRef">
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped>
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
textSize: 30,
|
textSize: 30,
|
||||||
patternColor: '#1b66c9',
|
patternColor: '#1b66c9',
|
||||||
patternList: defaultPatternList as number[],
|
patternList: defaultPatternList as number[],
|
||||||
|
background:{}, // 背景颜色或图片
|
||||||
},
|
},
|
||||||
musicList: defaultMusicList as IMusic[],
|
musicList: defaultMusicList as IMusic[],
|
||||||
imageList: defaultImageList as IImage[],
|
imageList: defaultImageList as IImage[],
|
||||||
@@ -93,8 +94,11 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
// 获取是否显示奖品列表
|
// 获取是否显示奖品列表
|
||||||
getIsShowPrizeList(state) {
|
getIsShowPrizeList(state) {
|
||||||
return state.globalConfig.isSHowPrizeList;
|
return state.globalConfig.isSHowPrizeList;
|
||||||
}
|
},
|
||||||
|
// 获取背景图片设置
|
||||||
|
getBackground(state){
|
||||||
|
return state.globalConfig.theme.background
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// 设置rowCount
|
// 设置rowCount
|
||||||
@@ -208,6 +212,10 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
setIsShowPrizeList(isShowPrizeList: boolean) {
|
setIsShowPrizeList(isShowPrizeList: boolean) {
|
||||||
this.globalConfig.isSHowPrizeList = isShowPrizeList;
|
this.globalConfig.isSHowPrizeList = isShowPrizeList;
|
||||||
},
|
},
|
||||||
|
// 设置背景图片
|
||||||
|
setBackground(background:{}){
|
||||||
|
this.globalConfig.theme.background = background
|
||||||
|
},
|
||||||
// 重置所有配置
|
// 重置所有配置
|
||||||
reset() {
|
reset() {
|
||||||
this.globalConfig = {
|
this.globalConfig = {
|
||||||
@@ -225,6 +233,7 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
textSize: 30,
|
textSize: 30,
|
||||||
patternColor: '#1b66c9',
|
patternColor: '#1b66c9',
|
||||||
patternList: defaultPatternList as number[],
|
patternList: defaultPatternList as number[],
|
||||||
|
background:{}, // 背景图片
|
||||||
},
|
},
|
||||||
musicList: defaultMusicList as IMusic[],
|
musicList: defaultMusicList as IMusic[],
|
||||||
imageList: defaultImageList as IImage[],
|
imageList: defaultImageList as IImage[],
|
||||||
|
|||||||
@@ -39,3 +39,33 @@ export function rgba(color: string, opacity: number) {
|
|||||||
|
|
||||||
return rgbaStr
|
return rgbaStr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function rgbToHex(color:string) {
|
||||||
|
// 去掉字符串中的空格
|
||||||
|
color = color.replace(/\s+/g, '');
|
||||||
|
|
||||||
|
// 匹配rgba或rgb格式的字符串
|
||||||
|
const rgbaMatch = color.match(/^rgba?\((\d+),(\d+),(\d+),?(\d*\.?\d+)?\)$/i);
|
||||||
|
if (!rgbaMatch) {
|
||||||
|
throw new Error('Invalid color format');
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = parseInt(rgbaMatch[1], 10);
|
||||||
|
const g = parseInt(rgbaMatch[2], 10);
|
||||||
|
const b = parseInt(rgbaMatch[3], 10);
|
||||||
|
const a = rgbaMatch[4] !== undefined ? parseFloat(rgbaMatch[4]) : undefined;
|
||||||
|
|
||||||
|
// 将RGB值转换为十六进制
|
||||||
|
let hex = "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
|
||||||
|
|
||||||
|
// 如果提供了alpha值,则将其转换为十六进制并附加到结果中
|
||||||
|
if (a !== undefined) {
|
||||||
|
let alphaHex = Math.round(a * 255).toString(16).toUpperCase();
|
||||||
|
if (alphaHex.length === 1) {
|
||||||
|
alphaHex = "0" + alphaHex; // 确保alpha值是两位数
|
||||||
|
}
|
||||||
|
hex += alphaHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
@@ -12,11 +12,24 @@ import PatternSetting from './components/PatternSetting.vue'
|
|||||||
|
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const personConfig = useStore().personConfig
|
const personConfig = useStore().personConfig
|
||||||
const prizeConfig= useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
const { getTopTitle: topTitle, getTheme: localTheme, getPatterColor: patternColor, getPatternList: patternList, getCardColor: cardColor, getLuckyColor: luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowPrizeList: isShowPrizeList } = storeToRefs(globalConfig)
|
const { getTopTitle: topTitle,
|
||||||
|
getTheme: localTheme,
|
||||||
|
getPatterColor: patternColor,
|
||||||
|
getPatternList: patternList,
|
||||||
|
getCardColor: cardColor,
|
||||||
|
getLuckyColor: luckyCardColor,
|
||||||
|
getTextColor: textColor,
|
||||||
|
getCardSize: cardSize,
|
||||||
|
getTextSize: textSize,
|
||||||
|
getRowCount: rowCount,
|
||||||
|
getIsShowPrizeList: isShowPrizeList,
|
||||||
|
getBackground: backgroundImage,
|
||||||
|
getImageList: imageList
|
||||||
|
} = storeToRefs(globalConfig)
|
||||||
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
|
const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
|
||||||
const colorPickerRef = ref()
|
const colorPickerRef = ref()
|
||||||
const resetDataDialogRef=ref()
|
const resetDataDialogRef = ref()
|
||||||
interface ThemeDaType {
|
interface ThemeDaType {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
@@ -33,13 +46,13 @@ const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
|
|||||||
const patternColorValue = ref(structuredClone(patternColor.value))
|
const patternColorValue = ref(structuredClone(patternColor.value))
|
||||||
const themeList = ref(Object.keys(daisyuiThemes))
|
const themeList = ref(Object.keys(daisyuiThemes))
|
||||||
const daisyuiThemeList = ref<ThemeDaType>(daisyuiThemes)
|
const daisyuiThemeList = ref<ThemeDaType>(daisyuiThemes)
|
||||||
|
const backgroundImageValue = ref(backgroundImage.value)
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
rowCount: rowCountValue,
|
rowCount: rowCountValue,
|
||||||
})
|
})
|
||||||
const formErr = ref({
|
const formErr = ref({
|
||||||
rowCount: '',
|
rowCount: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
const schema = zod.object({
|
const schema = zod.object({
|
||||||
rowCount: zod.number({
|
rowCount: zod.number({
|
||||||
required_error: '必填项',
|
required_error: '必填项',
|
||||||
@@ -85,7 +98,7 @@ const resetPattern = () => {
|
|||||||
globalConfig.resetPatternList()
|
globalConfig.resetPatternList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetData=()=>{
|
const resetData = () => {
|
||||||
globalConfig.reset();
|
globalConfig.reset();
|
||||||
personConfig.reset();
|
personConfig.reset();
|
||||||
prizeConfig.resetDefault();
|
prizeConfig.resetDefault();
|
||||||
@@ -138,13 +151,15 @@ watch(patternColorValue, (val: string) => {
|
|||||||
watch(textColorValue, (val: string) => {
|
watch(textColorValue, (val: string) => {
|
||||||
globalConfig.setTextColor(val)
|
globalConfig.setTextColor(val)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
watch(cardSizeValue, (val: { width: number; height: number; }) => {
|
watch(cardSizeValue, (val: { width: number; height: number; }) => {
|
||||||
globalConfig.setCardSize(val)
|
globalConfig.setCardSize(val)
|
||||||
}, { deep: true }),
|
}, { deep: true }),
|
||||||
watch(isShowPrizeListValue, () => {
|
watch(isShowPrizeListValue, () => {
|
||||||
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
||||||
})
|
})
|
||||||
|
watch(backgroundImageValue, (val: {}) => {
|
||||||
|
globalConfig.setBackground(val)
|
||||||
|
})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
@@ -192,7 +207,8 @@ onMounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="tooltip" data-tip="该项比较耗费时间和性能">
|
<div class="tooltip" data-tip="该项比较耗费时间和性能">
|
||||||
<button class="mt-5 btn btn-info btn-sm" :disabled="isRowCountChange != 1" @click="resetPersonLayout">
|
<button class="mt-5 btn btn-info btn-sm" :disabled="isRowCountChange != 1"
|
||||||
|
@click="resetPersonLayout">
|
||||||
<span>重设布局</span>
|
<span>重设布局</span>
|
||||||
<span class="loading loading-ring loading-md" v-show="isRowCountChange == 2"></span>
|
<span class="loading loading-ring loading-md" v-show="isRowCountChange == 2"></span>
|
||||||
</button>
|
</button>
|
||||||
@@ -208,11 +224,23 @@ onMounted(() => {
|
|||||||
<option v-for="(item, index) in themeList" :key="index" :value="item">{{ item }}</option>
|
<option v-for="(item, index) in themeList" :key="index" :value="item">{{ item }}</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">选择背景图片</span>
|
||||||
|
</div>
|
||||||
|
<select data-choose-theme class="w-full max-w-xs border-solid select border-1"
|
||||||
|
v-model="backgroundImageValue">
|
||||||
|
<option disabled selected>选取背景图片</option>
|
||||||
|
<option v-for="(item, index) in [{ name: '无', url: '', id: '' }, ...imageList]" :key="index"
|
||||||
|
:value="item">{{ item.name }}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
<label class="w-full max-w-xs form-control">
|
<label class="w-full max-w-xs form-control">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">卡片颜色</span>
|
<span class="label-text">卡片颜色</span>
|
||||||
</div>
|
</div>
|
||||||
<ColorPicker ref="colorPickerRef" v-model="cardColorValue" v-model:pure-color="cardColorValue"></ColorPicker>
|
<ColorPicker ref="colorPickerRef" v-model="cardColorValue" v-model:pure-color="cardColorValue">
|
||||||
|
</ColorPicker>
|
||||||
</label>
|
</label>
|
||||||
<label class="w-full max-w-xs form-control">
|
<label class="w-full max-w-xs form-control">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
@@ -226,7 +254,8 @@ onMounted(() => {
|
|||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">文字颜色</span>
|
<span class="label-text">文字颜色</span>
|
||||||
</div>
|
</div>
|
||||||
<ColorPicker ref="colorPickerRef" v-model="textColorValue" v-model:pure-color="textColorValue"></ColorPicker>
|
<ColorPicker ref="colorPickerRef" v-model="textColorValue" v-model:pure-color="textColorValue">
|
||||||
|
</ColorPicker>
|
||||||
</label>
|
</label>
|
||||||
<label class="flex flex-row w-full max-w-xs gap-10 mb-10 form-control">
|
<label class="flex flex-row w-full max-w-xs gap-10 mb-10 form-control">
|
||||||
<div>
|
<div>
|
||||||
@@ -284,7 +313,8 @@ onMounted(() => {
|
|||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">是否常显奖品列表</span>
|
<span class="label-text">是否常显奖品列表</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="checkbox" :checked="isShowPrizeListValue" @change="isShowPrizeListValue = !isShowPrizeListValue"
|
<input type="checkbox" :checked="isShowPrizeListValue"
|
||||||
|
@change="isShowPrizeListValue = !isShowPrizeListValue"
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,22 @@ const personConfig = useStore().personConfig
|
|||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const prizeConfig = useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
|
|
||||||
const { getAllPersonList: allPersonList, getNotPersonList: notPersonList, getNotThisPrizePersonList: notThisPrizePersonList } = storeToRefs(personConfig)
|
const { getAllPersonList: allPersonList,
|
||||||
|
getNotPersonList: notPersonList,
|
||||||
|
getNotThisPrizePersonList: notThisPrizePersonList
|
||||||
|
} = storeToRefs(personConfig)
|
||||||
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
||||||
const { getTopTitle: topTitle, getCardColor: cardColor, getPatterColor: patternColor, getPatternList: patternList, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount } = storeToRefs(globalConfig)
|
const { getTopTitle: topTitle,
|
||||||
|
getCardColor: cardColor,
|
||||||
|
getPatterColor: patternColor,
|
||||||
|
getPatternList: patternList,
|
||||||
|
getTextColor: textColor,
|
||||||
|
getLuckyColor: luckyColor,
|
||||||
|
getCardSize: cardSize,
|
||||||
|
getTextSize: textSize,
|
||||||
|
getRowCount: rowCount,
|
||||||
|
getBackground: homeBackground,
|
||||||
|
} = storeToRefs(globalConfig)
|
||||||
const tableData = ref<any[]>([])
|
const tableData = ref<any[]>([])
|
||||||
// const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value))))
|
// const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value))))
|
||||||
const currentStatus = ref(0) // 0为初始状态, 1为抽奖准备状态,2为抽奖中状态,3为抽奖结束状态
|
const currentStatus = ref(0) // 0为初始状态, 1为抽奖准备状态,2为抽奖中状态,3为抽奖结束状态
|
||||||
@@ -77,8 +90,8 @@ function initTableData() {
|
|||||||
tableData.value = tableData.value.concat(JSON.parse(JSON.stringify(orginPersonData)))
|
tableData.value = tableData.value.concat(JSON.parse(JSON.stringify(orginPersonData)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
tableData.value=orginPersonData.slice(0, totalCount)
|
tableData.value = orginPersonData.slice(0, totalCount)
|
||||||
}
|
}
|
||||||
tableData.value = filterData(tableData.value.slice(0, totalCount), rowCount.value)
|
tableData.value = filterData(tableData.value.slice(0, totalCount), rowCount.value)
|
||||||
}
|
}
|
||||||
@@ -356,9 +369,9 @@ const enterLottery = async () => {
|
|||||||
randomBallData()
|
randomBallData()
|
||||||
}
|
}
|
||||||
if (patternList.value.length) {
|
if (patternList.value.length) {
|
||||||
for(let i=0;i<patternList.value.length;i++){
|
for (let i = 0; i < patternList.value.length; i++) {
|
||||||
if(i<rowCount.value*7){
|
if (i < rowCount.value * 7) {
|
||||||
objects.value[patternList.value[i]-1].element.style.backgroundColor = rgba(cardColor.value, Math.random() * 0.5 + 0.25)
|
objects.value[patternList.value[i] - 1].element.style.backgroundColor = rgba(cardColor.value, Math.random() * 0.5 + 0.25)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -418,7 +431,7 @@ const startLottery = () => {
|
|||||||
}
|
}
|
||||||
toast.open({
|
toast.open({
|
||||||
message: `现在抽取${currentPrize.value.name} ${leftover}人`,
|
message: `现在抽取${currentPrize.value.name} ${leftover}人`,
|
||||||
type:'default',
|
type: 'default',
|
||||||
position: 'top-right',
|
position: 'top-right',
|
||||||
duration: 8000
|
duration: 8000
|
||||||
})
|
})
|
||||||
@@ -646,7 +659,8 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
<!-- 选中菜单结构 start-->
|
<!-- 选中菜单结构 start-->
|
||||||
<div id="menu">
|
<div id="menu">
|
||||||
<button class="btn-end " @click="enterLottery" v-if="currentStatus == 0 && tableData.length > 0">进入抽奖</button>
|
<button class="btn-end " @click="enterLottery"
|
||||||
|
v-if="currentStatus == 0 && tableData.length > 0">进入抽奖</button>
|
||||||
|
|
||||||
<div class="start" v-if="currentStatus == 1">
|
<div class="start" v-if="currentStatus == 1">
|
||||||
<button class="btn-start" @click="startLottery"><strong>开始</strong>
|
<button class="btn-start" @click="startLottery"><strong>开始</strong>
|
||||||
@@ -696,7 +710,7 @@ onUnmounted(() => {
|
|||||||
</div>
|
</div>
|
||||||
<!-- end -->
|
<!-- end -->
|
||||||
</div>
|
</div>
|
||||||
<StarsBackground></StarsBackground>
|
<StarsBackground :home-background="homeBackground"></StarsBackground>
|
||||||
|
|
||||||
<!-- <LuckyView :luckyPersonList="luckyTargets" ref="LuckyViewRef"></LuckyView> -->
|
<!-- <LuckyView :luckyPersonList="luckyTargets" ref="LuckyViewRef"></LuckyView> -->
|
||||||
<!-- <PlayMusic class="absolute right-0 bottom-1/2"></PlayMusic> -->
|
<!-- <PlayMusic class="absolute right-0 bottom-1/2"></PlayMusic> -->
|
||||||
|
|||||||
Reference in New Issue
Block a user