Date: Thu, 11 Dec 2025 23:18:10 +0800
Subject: [PATCH 4/4] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20=E7=95=8C?=
=?UTF-8?q?=E9=9D=A2=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=E9=87=8D=E6=9E=84?=
=?UTF-8?q?=EF=BC=8C=E6=8A=BD=E7=A6=BB=E9=80=BB=E8=BE=91=20#96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/components/FileUpload/index.vue | 13 +-
src/store/globalConfig.ts | 7 +-
src/utils/file.ts | 10 +
.../{PatternSetting.vue => PatternEdit.vue} | 0
.../FaceConfig/components/UploadDialog.vue | 75 +++
src/views/Config/Global/FaceConfig/index.vue | 467 ++----------------
.../Global/FaceConfig/parts/DataSetting.vue | 87 ++++
.../Global/FaceConfig/parts/LayoutSetting.vue | 91 ++++
.../FaceConfig/parts/PatternSetting.vue | 50 ++
.../Global/FaceConfig/parts/TextSetting.vue | 72 +++
.../Global/FaceConfig/parts/ThemeSetting.vue | 101 ++++
.../Config/Global/FaceConfig/parts/index.ts | 5 +
.../Config/Global/FaceConfig/useViewModel.ts | 207 ++++++++
.../MusicConfig/components/UploadDialog.vue | 1 -
14 files changed, 756 insertions(+), 430 deletions(-)
rename src/views/Config/Global/FaceConfig/components/{PatternSetting.vue => PatternEdit.vue} (100%)
create mode 100644 src/views/Config/Global/FaceConfig/components/UploadDialog.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/DataSetting.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/LayoutSetting.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/PatternSetting.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/TextSetting.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/ThemeSetting.vue
create mode 100644 src/views/Config/Global/FaceConfig/parts/index.ts
create mode 100644 src/views/Config/Global/FaceConfig/useViewModel.ts
diff --git a/src/components/FileUpload/index.vue b/src/components/FileUpload/index.vue
index 2b809f2..1cc2b5e 100644
--- a/src/components/FileUpload/index.vue
+++ b/src/components/FileUpload/index.vue
@@ -2,10 +2,11 @@
import type { IFileData } from './type'
import { ListMusic, Upload, X } from 'lucide-vue-next'
import { ref } from 'vue'
-import { readFileData } from '@/utils/file'
+import { readFileAsJsonData, readFileData } from '@/utils/file'
-defineProps<{
+const props = defineProps<{
limitType?: string
+ mode?: 'file' | 'json'
}>()
const emits = defineEmits<{
@@ -17,6 +18,14 @@ const fileData = ref
(null)
async function handleFileChange(e: Event) {
const file = ((e.target as HTMLInputElement).files as FileList)[0]
const type = file.type
+ if (props.mode === 'json') {
+ const fileRes = await readFileAsJsonData(file)
+ const jsonData = JSON.parse(fileRes)
+ fileData.value = { dataUrl: jsonData, fileName: file.name, type }
+ originFileName.value = file.name
+ emits('uploadFile', fileData.value)
+ return
+ }
const { dataUrl, fileName } = await readFileData(file)
fileData.value = { dataUrl, fileName, type }
originFileName.value = fileName
diff --git a/src/store/globalConfig.ts b/src/store/globalConfig.ts
index 738d3a8..d89d64a 100644
--- a/src/store/globalConfig.ts
+++ b/src/store/globalConfig.ts
@@ -127,6 +127,10 @@ export const useGlobalConfig = defineStore('global', {
},
},
actions: {
+ // 设置全局配置
+ setGlobalConfig(data: any) {
+ this.globalConfig = data
+ },
// 设置rowCount
setRowCount(rowCount: number) {
this.globalConfig.rowCount = rowCount
@@ -137,9 +141,8 @@ export const useGlobalConfig = defineStore('global', {
},
// 设置主题
setTheme(theme: any) {
- const { name, detail } = theme
+ const { name } = theme
this.globalConfig.theme.name = name
- this.globalConfig.theme.detail = detail
},
// 设置卡片颜色
setCardColor(cardColor: string) {
diff --git a/src/utils/file.ts b/src/utils/file.ts
index f4b05c7..fd4fd6a 100644
--- a/src/utils/file.ts
+++ b/src/utils/file.ts
@@ -23,3 +23,13 @@ export async function readLocalFileAsArraybuffer(path: string): Promise {
+ return new Promise((resolve) => {
+ const reader = new FileReader()
+ reader.readAsText(file, 'utf-8')
+ reader.onload = (ev: any) => {
+ resolve(ev.target.result)
+ }
+ })
+}
diff --git a/src/views/Config/Global/FaceConfig/components/PatternSetting.vue b/src/views/Config/Global/FaceConfig/components/PatternEdit.vue
similarity index 100%
rename from src/views/Config/Global/FaceConfig/components/PatternSetting.vue
rename to src/views/Config/Global/FaceConfig/components/PatternEdit.vue
diff --git a/src/views/Config/Global/FaceConfig/components/UploadDialog.vue b/src/views/Config/Global/FaceConfig/components/UploadDialog.vue
new file mode 100644
index 0000000..45002ff
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/components/UploadDialog.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/index.vue b/src/views/Config/Global/FaceConfig/index.vue
index 7603048..e94b45c 100644
--- a/src/views/Config/Global/FaceConfig/index.vue
+++ b/src/views/Config/Global/FaceConfig/index.vue
@@ -1,443 +1,60 @@
-
{{ t('viewTitle.globalSetting') }}
-
-
-
+
+
+
-
+
-
+
-
+
-
-
-
+
diff --git a/src/views/Config/Global/FaceConfig/parts/DataSetting.vue b/src/views/Config/Global/FaceConfig/parts/DataSetting.vue
new file mode 100644
index 0000000..9aa14f7
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/DataSetting.vue
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/parts/LayoutSetting.vue b/src/views/Config/Global/FaceConfig/parts/LayoutSetting.vue
new file mode 100644
index 0000000..31952c3
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/LayoutSetting.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/parts/PatternSetting.vue b/src/views/Config/Global/FaceConfig/parts/PatternSetting.vue
new file mode 100644
index 0000000..43439ac
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/PatternSetting.vue
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/parts/TextSetting.vue b/src/views/Config/Global/FaceConfig/parts/TextSetting.vue
new file mode 100644
index 0000000..e60fa4c
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/TextSetting.vue
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/parts/ThemeSetting.vue b/src/views/Config/Global/FaceConfig/parts/ThemeSetting.vue
new file mode 100644
index 0000000..f78b41b
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/ThemeSetting.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
diff --git a/src/views/Config/Global/FaceConfig/parts/index.ts b/src/views/Config/Global/FaceConfig/parts/index.ts
new file mode 100644
index 0000000..4ce76b6
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/parts/index.ts
@@ -0,0 +1,5 @@
+export { default as DataSetting } from './DataSetting.vue'
+export { default as LayoutSetting } from './LayoutSetting.vue'
+export { default as PatternSetting } from './PatternSetting.vue'
+export { default as TextSetting } from './TextSetting.vue'
+export { default as ThemeSetting } from './ThemeSetting.vue'
diff --git a/src/views/Config/Global/FaceConfig/useViewModel.ts b/src/views/Config/Global/FaceConfig/useViewModel.ts
new file mode 100644
index 0000000..1b35d30
--- /dev/null
+++ b/src/views/Config/Global/FaceConfig/useViewModel.ts
@@ -0,0 +1,207 @@
+import { storeToRefs } from 'pinia'
+import { onMounted, ref, watch } from 'vue'
+import { z as zod } from 'zod'
+import i18n, { languageList } from '@/locales/i18n'
+import useStore from '@/store'
+import { themeChange } from '@/utils'
+import { clearAllDbStore } from '@/utils/localforage'
+
+export function useViewModel() {
+ type ValidatePayload = zod.infer
+ const globalConfig = useStore().globalConfig
+ const personConfig = useStore().personConfig
+ const prizeConfig = useStore().prizeConfig
+ const { getGlobalConfig: globalConfigData, getTopTitle: topTitle, getTheme: localTheme, getPatterColor: patternColor, getPatternList: patternList, getCardColor: cardColor, getLuckyColor: luckyCardColor, getTextColor: textColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount, getIsShowPrizeList: isShowPrizeList, getLanguage: userLanguage, getBackground: backgroundImage, getFont: currentFont, getTitleFont: currentTitleFont, getTitleFontSyncGlobal: titleFontSyncGlobal, getImageList: imageList, getIsShowAvatar: isShowAvatar,
+ } = storeToRefs(globalConfig)
+ const { getAlreadyPersonList: alreadyPersonList, getNotPersonList: notPersonList } = storeToRefs(personConfig)
+
+ const isRowCountChange = ref(0) // 0未改变,1改变,2加载中
+ const themeValue = ref(localTheme.value.name)
+ const topTitleValue = ref(structuredClone(topTitle.value))
+ const cardColorValue = ref(structuredClone(cardColor.value))
+ const luckyCardColorValue = ref(structuredClone(luckyCardColor.value))
+ const textColorValue = ref(structuredClone(textColor.value))
+ const cardSizeValue = ref(structuredClone(cardSize.value))
+ const textSizeValue = ref(structuredClone(textSize.value))
+ const rowCountValue = ref(structuredClone(rowCount.value))
+ const languageValue = ref(structuredClone(userLanguage.value))
+ const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
+ const isShowAvatarValue = ref(structuredClone(isShowAvatar.value))
+ const patternColorValue = ref(structuredClone(patternColor.value))
+ const backgroundImageValue = ref(backgroundImage.value)
+ const currentFontValue = ref(structuredClone(currentFont.value))
+ const currentTitleFontValue = ref(structuredClone(currentTitleFont.value))
+ const titleFontSyncGlobalValue = ref(structuredClone(titleFontSyncGlobal.value))
+ const formData = ref({
+ rowCount: rowCountValue,
+ })
+ const formErr = ref({
+ rowCount: '',
+ })
+ const schema = zod.object({
+ rowCount: zod.number({
+ error: i18n.global.t('error.require'),
+ // required_error: i18n.global.t('error.require'),
+ // invalid_type_error: i18n.global.t('error.requireNumber'),
+ })
+ .min(1, i18n.global.t('error.minNumber1'))
+ .max(100, i18n.global.t('error.maxNumber100')),
+ // 格式化
+
+ })
+ const payload: ValidatePayload = {
+ rowCount: formData.value.rowCount,
+ }
+ function parseSchema(props: ValidatePayload) {
+ return schema.parseAsync(props)
+ }
+
+ function resetPersonLayout() {
+ isRowCountChange.value = 2
+ setTimeout(() => {
+ const alreadyLen = alreadyPersonList.value.length
+ const notLen = notPersonList.value.length
+ if (alreadyLen <= 0 && notLen <= 0) {
+ return
+ }
+ const allPersonList = alreadyPersonList.value.concat(notPersonList.value)
+ const newAlreadyPersonList = allPersonList.slice(0, alreadyLen)
+ const newNotPersonList = allPersonList.slice(alreadyLen, notLen + alreadyLen)
+ personConfig.deleteAllPerson()
+ personConfig.addNotPersonList(newNotPersonList)
+ personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
+
+ isRowCountChange.value = 0
+ }, 1000)
+ }
+
+ function clearPattern() {
+ globalConfig.setPatternList([] as number[])
+ }
+ function resetPattern() {
+ globalConfig.resetPatternList()
+ }
+
+ function resetData() {
+ globalConfig.reset()
+ personConfig.reset()
+ prizeConfig.resetDefault()
+ // 删除所有indexDb
+ clearAllDbStore()
+ // 刷新页面
+ window.location.reload()
+ }
+
+ function exportAllConfigData() {
+ // const globalConfigData = globalConfig.getGlobalConfig()
+ // console.log(globalConfigData.value)
+ // const globalConfigData = globalConfig.getGlobalConfig()
+ const dataStr = JSON.stringify(globalConfigData.value, null, 2)
+ const dataUri = `data:application/json;charset=utf-8,${encodeURIComponent(dataStr)}`
+
+ const exportFileDefaultName = 'global-config.json'
+
+ const linkElement = document.createElement('a')
+ linkElement.setAttribute('href', dataUri)
+ linkElement.setAttribute('download', exportFileDefaultName)
+ linkElement.click()
+ }
+ function importAllConfigData(data: any) {
+ globalConfig.setGlobalConfig(data)
+ window.location.reload()
+ }
+
+ watch(() => formData.value.rowCount, () => {
+ payload.rowCount = formData.value.rowCount
+ parseSchema(payload).then((res) => {
+ if (res.rowCount) {
+ isRowCountChange.value = 1
+ globalConfig.setRowCount(res.rowCount)
+ }
+ }).catch((err) => {
+ formErr.value.rowCount = err.issues[0].message
+ })
+ })
+
+ watch(topTitleValue, (val) => {
+ globalConfig.setTopTitle(val)
+ })
+ watch(themeValue, (val: any) => {
+ globalConfig.setTheme({ name: val })
+ themeChange(val)
+ }, { deep: true })
+
+ watch(cardColorValue, (val: string) => {
+ globalConfig.setCardColor(val)
+ }, { deep: true })
+ watch(luckyCardColorValue, (val: string) => {
+ globalConfig.setLuckyCardColor(val)
+ }, { deep: true })
+ watch(patternColorValue, (val: string) => {
+ globalConfig.setPatterColor(val)
+ })
+ watch(textColorValue, (val: string) => {
+ globalConfig.setTextColor(val)
+ }, { deep: true })
+
+ watch(cardSizeValue, (val: { width: number, height: number }) => {
+ globalConfig.setCardSize(val)
+ }, { deep: true })
+
+ watch(isShowPrizeListValue, () => {
+ globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
+ })
+ watch(backgroundImageValue, (val) => {
+ globalConfig.setBackground(val)
+ })
+ watch(currentFontValue, (val) => {
+ globalConfig.setFont(val)
+ document.documentElement.style.setProperty('--app-font-family', `"${val}", -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`)
+ })
+ watch(currentTitleFontValue, (val) => {
+ globalConfig.setTitleFont(val)
+ })
+ watch(titleFontSyncGlobalValue, (val) => {
+ globalConfig.setTitleFontSyncGlobal(val)
+ })
+ watch(languageValue, (val: string) => {
+ globalConfig.setLanguage(val)
+ })
+ watch(isShowAvatarValue, () => {
+ globalConfig.setIsShowAvatar(isShowAvatarValue.value)
+ })
+ onMounted(() => {
+ })
+ return {
+ resetData,
+ topTitleValue,
+ languageValue,
+ textSizeValue,
+ currentFontValue,
+ currentTitleFontValue,
+ titleFontSyncGlobalValue,
+ languageList,
+ formErr,
+ formData,
+ cardSizeValue,
+ isShowPrizeListValue,
+ isShowAvatarValue,
+ resetPersonLayout,
+ isRowCountChange,
+ themeValue,
+ backgroundImageValue,
+ cardColorValue,
+ luckyCardColorValue,
+ textColorValue,
+ patternColorValue,
+ imageList,
+ rowCount,
+ cardColor,
+ patternColor,
+ patternList,
+ clearPattern,
+ resetPattern,
+ exportAllConfigData,
+ importAllConfigData,
+ }
+}
diff --git a/src/views/Config/Global/MusicConfig/components/UploadDialog.vue b/src/views/Config/Global/MusicConfig/components/UploadDialog.vue
index f04b939..be5bc00 100644
--- a/src/views/Config/Global/MusicConfig/components/UploadDialog.vue
+++ b/src/views/Config/Global/MusicConfig/components/UploadDialog.vue
@@ -10,7 +10,6 @@ import FileUpload from '@/components/FileUpload/index.vue'
import useStore from '@/store'
const toast = useToast()
-const { t } = useI18n()
const limitType = ref('audio/*')
const visible = defineModel('visible', {
type: Boolean,