feat(imgConfig): 优化图片存储结构

新增uuid依赖用于生成唯一ID,改进图片上传功能中的本地存储结构,
使用uuid替代时间戳作为键名以避免冲突,并调整从indexedDB读取数据的方式。
This commit is contained in:
log1997
2025-12-04 13:47:28 +08:00
parent f062f7c9e6
commit cdd4972870
7 changed files with 309 additions and 284 deletions

View File

@@ -31,6 +31,7 @@
"sparticles": "^1.3.1", "sparticles": "^1.3.1",
"three": "^0.166.0", "three": "^0.166.0",
"three-css3d": "^1.0.6", "three-css3d": "^1.0.6",
"uuid": "^13.0.0",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-dompurify-html": "^5.2.0", "vue-dompurify-html": "^5.2.0",
"vue-i18n": "^11.1.12", "vue-i18n": "^11.1.12",

9
pnpm-lock.yaml generated
View File

@@ -53,6 +53,9 @@ importers:
three-css3d: three-css3d:
specifier: ^1.0.6 specifier: ^1.0.6
version: 1.0.6(three@0.166.0) version: 1.0.6(three@0.166.0)
uuid:
specifier: ^13.0.0
version: 13.0.0
vue: vue:
specifier: ^3.5.13 specifier: ^3.5.13
version: 3.5.13(typescript@5.5.3) version: 3.5.13(typescript@5.5.3)
@@ -5135,6 +5138,10 @@ packages:
util@0.10.4: util@0.10.4:
resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==}
uuid@13.0.0:
resolution: {integrity: sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==}
hasBin: true
vary@1.1.2: vary@1.1.2:
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
engines: {node: '>= 0.8'} engines: {node: '>= 0.8'}
@@ -10877,6 +10884,8 @@ snapshots:
dependencies: dependencies:
inherits: 2.0.3 inherits: 2.0.3
uuid@13.0.0: {}
vary@1.1.2: {} vary@1.1.2: {}
vite-dev-rpc@1.1.0(vite@7.1.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.81.0)(terser@5.36.0)(yaml@2.8.1)): vite-dev-rpc@1.1.0(vite@7.1.6(@types/node@24.5.2)(jiti@2.5.1)(lightningcss@1.30.1)(sass@1.81.0)(terser@5.36.0)(yaml@2.8.1)):

View File

@@ -18,7 +18,8 @@ async function getImageStoreItem(item: any): Promise<string> {
let image = '' let image = ''
if (item.url === 'Storage') { if (item.url === 'Storage') {
const key = item.id const key = item.id
image = await imageDbStore.getItem(key) as string const imageData = await imageDbStore.getItem(key) as any
image = imageData.dataUrl
} }
else { else {
image = item.url image = item.url

View File

@@ -1,280 +1,280 @@
import type { IImage, IMusic } from '@/types/storeType' import type { IImage, IMusic } from '@/types/storeType'
import i18n, { browserLanguage } from '@/locales/i18n'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import i18n, { browserLanguage } from '@/locales/i18n'
import { defaultImageList, defaultMusicList, defaultPatternList } from './data' import { defaultImageList, defaultMusicList, defaultPatternList } from './data'
// import { IPrizeConfig } from '@/types/storeType'; // import { IPrizeConfig } from '@/types/storeType';
export const useGlobalConfig = defineStore('global', { export const useGlobalConfig = defineStore('global', {
state() { state() {
return { return {
globalConfig: { globalConfig: {
rowCount: 17, rowCount: 17,
isSHowPrizeList: true, isSHowPrizeList: true,
isShowAvatar: false, isShowAvatar: false,
topTitle: i18n.global.t('data.defaultTitle'), topTitle: i18n.global.t('data.defaultTitle'),
language: browserLanguage, language: browserLanguage,
theme: { theme: {
name: 'dracula', name: 'dracula',
detail: { primary: '#0f5fd3' }, detail: { primary: '#0f5fd3' },
cardColor: '#ff79c6', cardColor: '#ff79c6',
cardWidth: 140, cardWidth: 140,
cardHeight: 200, cardHeight: 200,
textColor: '#ffffff', textColor: '#ffffff',
luckyCardColor: '#ECB1AC', luckyCardColor: '#ECB1AC',
textSize: 30, textSize: 30,
patternColor: '#1b66c9', patternColor: '#1b66c9',
patternList: defaultPatternList as number[], patternList: defaultPatternList as number[],
background: {}, // 背景颜色或图片 background: {}, // 背景颜色或图片
},
musicList: defaultMusicList as IMusic[],
imageList: defaultImageList as IImage[],
},
currentMusic: {
item: defaultMusicList[0],
paused: true,
},
}
},
getters: {
// 获取全部配置
getGlobalConfig(state) {
return state.globalConfig
}, },
musicList: defaultMusicList as IMusic[], // 获取标题
imageList: defaultImageList as IImage[], getTopTitle(state) {
}, return state.globalConfig.topTitle
currentMusic: { },
item: defaultMusicList[0], // 获取行数
paused: true, getRowCount(state) {
}, return state.globalConfig.rowCount
} },
}, // 获取主题
getters: { getTheme(state) {
// 获取全部配置 return state.globalConfig.theme
getGlobalConfig(state) { },
return state.globalConfig // 获取卡片颜色
}, getCardColor(state) {
// 获取标题 return state.globalConfig.theme.cardColor
getTopTitle(state) { },
return state.globalConfig.topTitle // 获取中奖颜色
}, getLuckyColor(state) {
// 获取行数 return state.globalConfig.theme.luckyCardColor
getRowCount(state) { },
return state.globalConfig.rowCount // 获取文字颜色
}, getTextColor(state) {
// 获取主题 return state.globalConfig.theme.textColor
getTheme(state) { },
return state.globalConfig.theme // 获取卡片宽高
}, getCardSize(state) {
// 获取卡片颜色 return {
getCardColor(state) { width: state.globalConfig.theme.cardWidth,
return state.globalConfig.theme.cardColor height: state.globalConfig.theme.cardHeight,
}, }
// 获取中奖颜色 },
getLuckyColor(state) { // 获取文字大小
return state.globalConfig.theme.luckyCardColor getTextSize(state) {
}, return state.globalConfig.theme.textSize
// 获取文字颜色 },
getTextColor(state) { // 获取图案颜色
return state.globalConfig.theme.textColor getPatterColor(state) {
}, return state.globalConfig.theme.patternColor
// 获取卡片宽高 },
getCardSize(state) { // 获取图案列表
return { getPatternList(state) {
width: state.globalConfig.theme.cardWidth, return state.globalConfig.theme.patternList
height: state.globalConfig.theme.cardHeight, },
} // 获取音乐列表
}, getMusicList(state) {
// 获取文字大小 return state.globalConfig.musicList
getTextSize(state) { },
return state.globalConfig.theme.textSize // 获取当前音乐
}, getCurrentMusic(state) {
// 获取图案颜色 return state.currentMusic
getPatterColor(state) { },
return state.globalConfig.theme.patternColor // 获取图片列表
}, getImageList(state) {
// 获取图案列表 return state.globalConfig.imageList
getPatternList(state) { },
return state.globalConfig.theme.patternList // 获取是否显示奖品列表
}, getIsShowPrizeList(state) {
// 获取音乐列表 return state.globalConfig.isSHowPrizeList
getMusicList(state) { },
return state.globalConfig.musicList // 获取当前语言
}, getLanguage(state) {
// 获取当前音乐 return state.globalConfig.language
getCurrentMusic(state) { },
return state.currentMusic // 获取背景图片设置
}, getBackground(state) {
// 获取图片列表 return state.globalConfig.theme.background
getImageList(state) { },
return state.globalConfig.imageList // 获取是否显示头像
}, getIsShowAvatar(state) {
// 获取是否显示奖品列表 return state.globalConfig.isShowAvatar
getIsShowPrizeList(state) {
return state.globalConfig.isSHowPrizeList
},
// 获取当前语言
getLanguage(state) {
return state.globalConfig.language
},
// 获取背景图片设置
getBackground(state) {
return state.globalConfig.theme.background
},
// 获取是否显示头像
getIsShowAvatar(state) {
return state.globalConfig.isShowAvatar
},
},
actions: {
// 设置rowCount
setRowCount(rowCount: number) {
this.globalConfig.rowCount = rowCount
},
// 设置标题
setTopTitle(topTitle: string) {
this.globalConfig.topTitle = topTitle
},
// 设置主题
setTheme(theme: any) {
const { name, detail } = theme
this.globalConfig.theme.name = name
this.globalConfig.theme.detail = detail
},
// 设置卡片颜色
setCardColor(cardColor: string) {
this.globalConfig.theme.cardColor = cardColor
},
// 设置中奖颜色
setLuckyCardColor(luckyCardColor: string) {
this.globalConfig.theme.luckyCardColor = luckyCardColor
},
// 设置文字颜色
setTextColor(textColor: string) {
this.globalConfig.theme.textColor = textColor
},
// 设置卡片宽高
setCardSize(cardSize: { width: number, height: number }) {
this.globalConfig.theme.cardWidth = cardSize.width
this.globalConfig.theme.cardHeight = cardSize.height
},
// 设置文字大小
setTextSize(textSize: number) {
this.globalConfig.theme.textSize = textSize
},
// 设置图案颜色
setPatterColor(patterColor: string) {
this.globalConfig.theme.patternColor = patterColor
},
// 设置图案列表
setPatternList(patternList: number[]) {
this.globalConfig.theme.patternList = patternList
},
// 重置图案列表
resetPatternList() {
this.globalConfig.theme.patternList = defaultPatternList
},
// 添加音乐
addMusic(music: IMusic) {
// 验证音乐是否已存在看name字段
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
if (this.globalConfig.musicList[i].name === music.name) {
return
}
}
this.globalConfig.musicList.push(music)
},
// 删除音乐
removeMusic(musicId: string) {
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
if (this.globalConfig.musicList[i].id === musicId) {
this.globalConfig.musicList.splice(i, 1)
break
}
}
},
// 设置当前播放音乐
setCurrentMusic(musicItem: IMusic, paused: boolean = true) {
this.currentMusic = {
item: musicItem,
paused,
}
},
// 重置音乐列表
resetMusicList() {
this.globalConfig.musicList = JSON.parse(JSON.stringify(defaultMusicList)) as IMusic[]
},
// 清空音乐列表
clearMusicList() {
this.globalConfig.musicList = [] as IMusic[]
},
// 添加图片
addImage(image: IImage) {
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
if (this.globalConfig.imageList[i].name === image.name) {
return
}
}
this.globalConfig.imageList.push(image)
},
// 删除图片
removeImage(imageId: string) {
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
if (this.globalConfig.imageList[i].id === imageId) {
this.globalConfig.imageList.splice(i, 1)
break
}
}
},
// 重置图片列表
resetImageList() {
this.globalConfig.imageList = defaultImageList as IImage[]
},
// 清空图片列表
clearImageList() {
this.globalConfig.imageList = [] as IImage[]
},
// 设置是否显示奖品列表
setIsShowPrizeList(isShowPrizeList: boolean) {
this.globalConfig.isSHowPrizeList = isShowPrizeList
},
// 设置
setLanguage(language: string) {
this.globalConfig.language = language
i18n.global.locale.value = language
},
// 设置背景图片
setBackground(background: any) {
this.globalConfig.theme.background = background
},
// 设置是否显示头像
setIsShowAvatar(isShowAvatar: boolean) {
this.globalConfig.isShowAvatar = isShowAvatar
},
// 重置所有配置
reset() {
this.globalConfig = {
rowCount: 17,
isSHowPrizeList: true,
isShowAvatar: false,
topTitle: i18n.global.t('data.defaultTitle'),
language: browserLanguage,
theme: {
name: 'dracula',
detail: { primary: '#0f5fd3' },
cardColor: '#ff79c6',
cardWidth: 140,
cardHeight: 200,
textColor: '#ffffff',
luckyCardColor: '#ECB1AC',
textSize: 30,
patternColor: '#1b66c9',
patternList: defaultPatternList as number[],
background: {}, // 背景颜色或图片
}, },
musicList: defaultMusicList as IMusic[],
imageList: defaultImageList as IImage[],
}
this.currentMusic = {
item: defaultMusicList[0],
paused: true,
}
}, },
}, actions: {
persist: { // 设置rowCount
enabled: true, setRowCount(rowCount: number) {
strategies: [ this.globalConfig.rowCount = rowCount
{ },
// 如果要存储在localStorage中 // 设置标题
storage: localStorage, setTopTitle(topTitle: string) {
key: 'globalConfig', this.globalConfig.topTitle = topTitle
paths: ['globalConfig'], },
}, // 设置主题
], setTheme(theme: any) {
}, const { name, detail } = theme
this.globalConfig.theme.name = name
this.globalConfig.theme.detail = detail
},
// 设置卡片颜色
setCardColor(cardColor: string) {
this.globalConfig.theme.cardColor = cardColor
},
// 设置中奖颜色
setLuckyCardColor(luckyCardColor: string) {
this.globalConfig.theme.luckyCardColor = luckyCardColor
},
// 设置文字颜色
setTextColor(textColor: string) {
this.globalConfig.theme.textColor = textColor
},
// 设置卡片宽高
setCardSize(cardSize: { width: number, height: number }) {
this.globalConfig.theme.cardWidth = cardSize.width
this.globalConfig.theme.cardHeight = cardSize.height
},
// 设置文字大小
setTextSize(textSize: number) {
this.globalConfig.theme.textSize = textSize
},
// 设置图案颜色
setPatterColor(patterColor: string) {
this.globalConfig.theme.patternColor = patterColor
},
// 设置图案列表
setPatternList(patternList: number[]) {
this.globalConfig.theme.patternList = patternList
},
// 重置图案列表
resetPatternList() {
this.globalConfig.theme.patternList = defaultPatternList
},
// 添加音乐
addMusic(music: IMusic) {
// 验证音乐是否已存在看name字段
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
if (this.globalConfig.musicList[i].name === music.name) {
return
}
}
this.globalConfig.musicList.push(music)
},
// 删除音乐
removeMusic(musicId: string) {
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
if (this.globalConfig.musicList[i].id === musicId) {
this.globalConfig.musicList.splice(i, 1)
break
}
}
},
// 设置当前播放音乐
setCurrentMusic(musicItem: IMusic, paused: boolean = true) {
this.currentMusic = {
item: musicItem,
paused,
}
},
// 重置音乐列表
resetMusicList() {
this.globalConfig.musicList = JSON.parse(JSON.stringify(defaultMusicList)) as IMusic[]
},
// 清空音乐列表
clearMusicList() {
this.globalConfig.musicList = [] as IMusic[]
},
// 添加图片
addImage(image: IImage) {
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
if (this.globalConfig.imageList[i].name === image.name) {
return
}
}
this.globalConfig.imageList.push(image)
},
// 删除图片
removeImage(imageId: string) {
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
if (this.globalConfig.imageList[i].id === imageId) {
this.globalConfig.imageList.splice(i, 1)
break
}
}
},
// 重置图片列表
resetImageList() {
this.globalConfig.imageList = defaultImageList as IImage[]
},
// 清空图片列表
clearImageList() {
this.globalConfig.imageList = [] as IImage[]
},
// 设置是否显示奖品列表
setIsShowPrizeList(isShowPrizeList: boolean) {
this.globalConfig.isSHowPrizeList = isShowPrizeList
},
// 设置
setLanguage(language: string) {
this.globalConfig.language = language
i18n.global.locale.value = language
},
// 设置背景图片
setBackground(background: any) {
this.globalConfig.theme.background = background
},
// 设置是否显示头像
setIsShowAvatar(isShowAvatar: boolean) {
this.globalConfig.isShowAvatar = isShowAvatar
},
// 重置所有配置
reset() {
this.globalConfig = {
rowCount: 17,
isSHowPrizeList: true,
isShowAvatar: false,
topTitle: i18n.global.t('data.defaultTitle'),
language: browserLanguage,
theme: {
name: 'dracula',
detail: { primary: '#0f5fd3' },
cardColor: '#ff79c6',
cardWidth: 140,
cardHeight: 200,
textColor: '#ffffff',
luckyCardColor: '#ECB1AC',
textSize: 30,
patternColor: '#1b66c9',
patternList: defaultPatternList as number[],
background: {}, // 背景颜色或图片
},
musicList: defaultMusicList as IMusic[],
imageList: defaultImageList as IImage[],
}
this.currentMusic = {
item: defaultMusicList[0],
paused: true,
}
},
},
persist: {
enabled: true,
strategies: [
{
// 如果要存储在localStorage中
storage: localStorage,
key: 'globalConfig',
paths: ['globalConfig'],
},
],
},
}) })

View File

@@ -0,0 +1,13 @@
import localforage from 'localforage'
const imageDbStore = localforage.createInstance({
name: 'imgStore',
})
async function clearImageDbStore() {
await imageDbStore.clear()
}
export function clearAllDbStore() {
clearImageDbStore()
}

View File

@@ -1,4 +1,5 @@
<script setup lang='ts'> <script setup lang='ts'>
import localforage from 'localforage'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { onMounted, ref, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { ColorPicker } from 'vue3-colorpicker' import { ColorPicker } from 'vue3-colorpicker'
@@ -8,6 +9,7 @@ import { daisyuiThemes } from '@/constant/theme'
import i18n, { languageList } from '@/locales/i18n' import i18n, { languageList } from '@/locales/i18n'
import useStore from '@/store' import useStore from '@/store'
import { themeChange } from '@/utils' import { themeChange } from '@/utils'
import { clearAllDbStore } from '@/utils/localforage'
import PatternSetting from './components/PatternSetting.vue' import PatternSetting from './components/PatternSetting.vue'
import 'vue3-colorpicker/style.css' import 'vue3-colorpicker/style.css'
@@ -94,18 +96,12 @@ function resetData() {
globalConfig.reset() globalConfig.reset()
personConfig.reset() personConfig.reset()
prizeConfig.resetDefault() prizeConfig.resetDefault()
// 删除所有indexDb
clearAllDbStore()
// 刷新页面 // 刷新页面
window.location.reload() window.location.reload()
} }
// const handleChangeShowFields = (fieldItem: any) => {
// formData.value.showField.map((item) => {
// if (item.label === fieldItem.label) {
// item.value = !item.value
// }
// })
// }
watch(() => formData.value.rowCount, () => { watch(() => formData.value.rowCount, () => {
payload.rowCount = formData.value.rowCount payload.rowCount = formData.value.rowCount
parseSchema(payload).then((res) => { parseSchema(payload).then((res) => {

View File

@@ -1,6 +1,7 @@
<script setup lang='ts'> <script setup lang='ts'>
import type { IFileData } from '@/components/ImageUpload/type' import type { IFileData } from '@/components/ImageUpload/type'
import localforage from 'localforage' import localforage from 'localforage'
import { v4 as uuidv4 } from 'uuid'
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import CustomDialog from '@/components/Dialog/index.vue' import CustomDialog from '@/components/Dialog/index.vue'
@@ -47,10 +48,11 @@ async function uploadFile(fileData: IFileData | null) {
async function getImageDbStore() { async function getImageDbStore() {
const keys = await imageDbStore.keys() const keys = await imageDbStore.keys()
if (keys.length > 0) { if (keys.length > 0) {
imageDbStore.iterate((value, key) => { imageDbStore.iterate((value: { fileName: string, dataUrl: string }, key: string) => {
console.log(value, key)
globalConfig.addImage({ globalConfig.addImage({
id: key, id: key,
name: key, name: value.fileName,
url: 'Storage', url: 'Storage',
}) })
}) })
@@ -59,8 +61,11 @@ async function getImageDbStore() {
function submitUpload() { function submitUpload() {
if (imageData.value) { if (imageData.value) {
const { dataUrl, fileName } = imageData.value const { dataUrl, fileName } = imageData.value
console.log(dataUrl, fileName) const uniqueId = uuidv4()
imageDbStore.setItem(`${new Date().getTime().toString()}+${fileName}`, dataUrl) imageDbStore.setItem(uniqueId, {
dataUrl,
fileName,
})
.then(() => { .then(() => {
imgUploadToast.value = 1 imgUploadToast.value = 1
getImageDbStore() getImageDbStore()