feat: 国际化
This commit is contained in:
@@ -1,12 +0,0 @@
|
|||||||
.md
|
|
||||||
node_modules
|
|
||||||
public
|
|
||||||
package.json
|
|
||||||
*.yaml
|
|
||||||
.gitignore
|
|
||||||
.eslintrc*
|
|
||||||
.babelrc
|
|
||||||
.eslintignore
|
|
||||||
.commitlintrc*
|
|
||||||
.env*
|
|
||||||
tsconfig*
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
browser: true,
|
|
||||||
es2021: true,
|
|
||||||
node: true,
|
|
||||||
},
|
|
||||||
extends: [
|
|
||||||
"eslint:recommended",
|
|
||||||
"plugin:vue/vue3-essential",
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
],
|
|
||||||
overrides: [],
|
|
||||||
parser: "vue-eslint-parser",
|
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: "latest",
|
|
||||||
parser: "@typescript-eslint/parser",
|
|
||||||
sourceType: "module",
|
|
||||||
},
|
|
||||||
plugins: ["vue", "@typescript-eslint"],
|
|
||||||
rules: {
|
|
||||||
"@typescript-eslint/ban-types": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
extendDefaults: true,
|
|
||||||
types: {
|
|
||||||
"{}": false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
// 关闭typescript类型为any的警告
|
|
||||||
"@typescript-eslint/no-explicit-any": ["off"],
|
|
||||||
// 驼峰命名,但忽略index
|
|
||||||
"vue/multi-word-component-names": [
|
|
||||||
"error",
|
|
||||||
{
|
|
||||||
ignores: ["index"], //需要忽略的组件名
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"no-console": "warn",
|
|
||||||
"no-debugger": "warn",
|
|
||||||
// complexity: ["warn", { max: 5 }],
|
|
||||||
// 禁止使用多个空格
|
|
||||||
"no-multi-spaces": "error",
|
|
||||||
// 最大连续空行数
|
|
||||||
"no-multiple-empty-lines": ["error", { max: 2, maxEOF: 1, maxBOF: 0 }],
|
|
||||||
// 代码块中去除前后空行
|
|
||||||
"padded-blocks": ["error", "never"],
|
|
||||||
// 使用单引号,字符串中包含了一个其它引号 允许"a string containing 'single' quotes"
|
|
||||||
quotes: ["error", "single", { avoidEscape: true }],
|
|
||||||
// return之前必须空行
|
|
||||||
"newline-before-return": "error",
|
|
||||||
//文件末尾强制换行
|
|
||||||
"eol-last": ["error", "always"],
|
|
||||||
//禁止空格和 tab 的混合缩进
|
|
||||||
"no-mixed-spaces-and-tabs": ["error", "smart-tabs"],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
2
.github/workflows/node.js.yml
vendored
2
.github/workflows/node.js.yml
vendored
@@ -4,8 +4,6 @@
|
|||||||
name: Node.js CI
|
name: Node.js CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ "main" ]
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -6,7 +6,7 @@ yarn-debug.log*
|
|||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
lerna-debug.log*
|
lerna-debug.log*
|
||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
pnpm-lock.yaml
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
@@ -128,3 +128,4 @@ dist
|
|||||||
.yarn/build-state.yml
|
.yarn/build-state.yml
|
||||||
.yarn/install-state.gz
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.pnp.*
|
||||||
|
target
|
||||||
@@ -46,6 +46,7 @@ or
|
|||||||
- [x] 🧨 国际化多语言
|
- [x] 🧨 国际化多语言
|
||||||
- [x] 🍃 更换背景图片
|
- [x] 🍃 更换背景图片
|
||||||
- [x] 🚅 添加docker构建
|
- [x] 🚅 添加docker构建
|
||||||
|
- [x] 😘 弹幕(开发中)
|
||||||
- [ ] 🧵 卡片组成多种形状
|
- [ ] 🧵 卡片组成多种形状
|
||||||
|
|
||||||
...
|
...
|
||||||
|
|||||||
7
eslint.config.js
Normal file
7
eslint.config.js
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import antfu from '@antfu/eslint-config'
|
||||||
|
|
||||||
|
export default antfu(
|
||||||
|
{
|
||||||
|
ignores: ['**/node_modules', '**/public', '**/dist', '**/package.json', '**/*.yaml', '**/.gitignore', '**/.env*', '**/tsconfig*'],
|
||||||
|
},
|
||||||
|
)
|
||||||
@@ -12,7 +12,8 @@
|
|||||||
"test": "vitest",
|
"test": "vitest",
|
||||||
"test:ui": "vitest --ui",
|
"test:ui": "vitest --ui",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"lint": "eslint ./src --ext .vue,.js,.ts,.jsx,.tsx --fix"
|
"lint": "eslint ./src",
|
||||||
|
"lint:fix": "eslint ./src --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tweenjs/tween.js": "^23.1.2",
|
"@tweenjs/tween.js": "^23.1.2",
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
"three-css3d": "^1.0.6",
|
"three-css3d": "^1.0.6",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-dompurify-html": "^5.2.0",
|
"vue-dompurify-html": "^5.2.0",
|
||||||
|
"vue-i18n": "^10.0.4",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"vue-toast-notification": "^3",
|
"vue-toast-notification": "^3",
|
||||||
"vue3-colorpicker": "^2.3.0",
|
"vue3-colorpicker": "^2.3.0",
|
||||||
@@ -38,6 +40,9 @@
|
|||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@antfu/eslint-config": "^3.9.2",
|
||||||
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
|
"@eslint/js": "^9.15.0",
|
||||||
"@iconify-json/ep": "^1.2.1",
|
"@iconify-json/ep": "^1.2.1",
|
||||||
"@iconify-json/fluent": "^1.2.8",
|
"@iconify-json/fluent": "^1.2.8",
|
||||||
"@tailwindcss/typography": "^0.5.15",
|
"@tailwindcss/typography": "^0.5.15",
|
||||||
@@ -56,6 +61,7 @@
|
|||||||
"daisyui": "^4.12.14",
|
"daisyui": "^4.12.14",
|
||||||
"eslint": "^9.15.0",
|
"eslint": "^9.15.0",
|
||||||
"eslint-plugin-vue": "^9.31.0",
|
"eslint-plugin-vue": "^9.31.0",
|
||||||
|
"globals": "^15.12.0",
|
||||||
"happy-dom": "^15.11.6",
|
"happy-dom": "^15.11.6",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"jsdom": "^25.0.1",
|
"jsdom": "^25.0.1",
|
||||||
|
|||||||
1707
pnpm-lock.yaml
generated
1707
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1 +1 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1705479543818" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4421" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M341.333333 618.666667l-179.2 174.933333C185.6 834.133333 149.333333 853.333333 149.333333 853.333333s-27.733333-34.133333-53.333333-64c-14.933333-17.066667-14.933333-40.533333 10.666667-64l149.333333-149.333333 106.666667 42.666667h-21.333334z m554.666667-296.533334s-44.8-12.8-64 17.066667v2.133333l-196.266667 21.333334 8.533334 85.333333 166.4-21.333333s27.733333 2.133333 42.666666-21.333334 42.666667-83.2 42.666667-83.2zM253.866667 541.866667c4.266667-10.666667-2.133333-23.466667-12.8-27.733334-4.266667-2.133333-93.866667-36.266667-93.866667-132.266666 0-12.8-8.533333-21.333333-21.333333-21.333334s-21.333333 8.533333-21.333334 21.333334c0 125.866667 106.666667 174.933333 113.066667 177.066666 2.133333 0 14.933333-2.133333 17.066667-2.133333 8.533333-2.133333 17.066667-6.4 19.2-14.933333zM597.333333 149.333333s-57.6-44.8-106.666666 0c0 0 42.666667 44.8 64 85.333334 93.866667-44.8 42.666667-85.333333 42.666666-85.333334z" fill="#844419" p-id="4422"></path><path d="M896 128m-42.666667 0a42.666667 42.666667 0 1 0 85.333334 0 42.666667 42.666667 0 1 0-85.333334 0Z" fill="#E91E63" p-id="4423"></path><path d="M917.333333 469.333333s-46.933333 53.333333-66.133333 76.8c-17.066667 17.066667-46.933333 4.266667-46.933333 4.266667l-147.2-46.933333c-12.8 17.066667-32 34.133333-59.733334 51.2-40.533333 27.733333-106.666667 51.2-172.8 66.133333L341.333333 746.666667l-42.666666 128c38.4 2.133333 42.666667 42.666667 42.666666 42.666666s-61.866667 4.266667-85.333333 0-51.2-32-42.666667-64l55.466667-183.466666c-6.4-12.8-17.066667-29.866667-34.133333-51.2-59.733333-74.666667 21.333333-128 21.333333-128s206.933333-134.4 256-170.666667c32-23.466667 40.533333-61.866667 42.666667-85.333333 93.866667-44.8 42.666667-85.333333 42.666666-85.333334s-2.133333-2.133333-4.266666-2.133333c12.8-8.533333 27.733333-14.933333 46.933333-19.2 49.066667-12.8 49.066667 21.333333 149.333333 21.333333 49.066667 0 10.666667 83.2-42.666666 106.666667-36.266667 14.933333-85.333333 49.066667-85.333334 85.333333 0 17.066667 17.066667 44.8 21.333334 81.066667l168.533333 49.066667s2.133333-4.266667 4.266667-4.266667c34.133333-25.6 61.866667 2.133333 61.866666 2.133333zM522.666667 185.6c23.466667-19.2 49.066667-40.533333 70.4-40.533333l-12.8-6.4c-21.333333-10.666667-57.6-19.2-89.6 10.666666 0 0-34.133333 44.8-17.066667 61.866667 8.533333 8.533333 27.733333-6.4 49.066667-25.6z" fill="#CC6C25" p-id="4424"></path><path d="M789.333333 149.333333h-21.333333s10.666667 34.133333 38.4 42.666667c8.533333-23.466667 6.4-42.666667-17.066667-42.666667z" fill="#5D4037" p-id="4425"></path><path d="M704 170.666667c0 12.8-8.533333 21.333333-21.333333 21.333333s-21.333333-21.333333-21.333334-21.333333 8.533333-21.333333 21.333334-21.333334 21.333333 8.533333 21.333333 21.333334z" fill="#3E2723" p-id="4426"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><path fill="#FFF" d="M128 249.018C61.09 249.018 6.982 194.91 6.982 128S61.09 6.982 128 6.982S249.018 61.091 249.018 128c0 66.91-54.109 121.018-121.018 121.018Z"/><path fill="#3F3F3F" d="M128 14.545c62.836 0 113.455 51.2 113.455 113.455c0 62.255-50.619 113.455-113.455 113.455S14.545 190.836 14.545 128S65.164 14.545 128 14.545ZM128 0C57.018 0 0 57.018 0 128s57.018 128 128 128s128-57.018 128-128S197.818 0 128 0Z"/><path fill="#0AB3E5" d="m74.473 119.273l23.272 18.618l32-52.364l40.728 65.164l22.109-17.455l24.436 36.073c5.818-12.8 10.473-27.927 10.473-42.473c0-55.272-43.636-98.909-98.91-98.909c-55.272 0-100.654 44.8-100.654 98.91c0 17.454 4.655 32 11.637 46.545l34.909-54.11Z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 772 B |
BIN
public/personListTemplate-en.xlsx
Normal file
BIN
public/personListTemplate-en.xlsx
Normal file
Binary file not shown.
31
public/readme-en.md
Normal file
31
public/readme-en.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
# Operation Guide
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. Upon first entry, no data will be displayed. You can choose to use default data to view the overall display effect. It is recommended to import your own data for operation. The steps are as follows:
|
||||||
|
|
||||||
|
a. Personnel Configuration - Personnel List - Download Template, download the data template and modify it with your data (please note that the header cannot be modified).
|
||||||
|
|
||||||
|
b. After modification, click 'Upload File' on the same page to upload the modified Excel table.
|
||||||
|
|
||||||
|
2. Enter the Prize Configuration to modify your prize information. Try to keep the name short for better display; "All Participants" indicates whether this award will be drawn from all participants (those who have already won can still participate); "Winners" refers to the number of people to be drawn for this award; "Already Won" cannot be edited; "Selected" means this award has been used, unselecting it will reset the award but not the winners; "Image" is the prize image displayed on the home page (you can upload images in the image list); "Left Icon" is used to adjust the order of prizes.
|
||||||
|
|
||||||
|
Completing the above two steps allows normal use.
|
||||||
|
|
||||||
|
## Function Description
|
||||||
|
|
||||||
|
1. Add Temporary Draw: There is a '+' button in the prize list on the draw page. Clicking it allows you to add a temporary draw. Note: Only one temporary draw can be added at a time. After adding successfully, the current prize will be set to the temporary prize, and after drawing, it will return to the normal prize list.
|
||||||
|
2. Music and Image List: You can upload files yourself for use. After uploading images successfully, you can select them in the prize configuration for display. After uploading music successfully, it will be added to the play list.
|
||||||
|
3. Music Playback: Left-click with the mouse to play/pause, right-click to play the next song.
|
||||||
|
4. Interface Configuration - Pattern Settings: You can use the mouse to click and customize the highlighted patterns on the home page.
|
||||||
|
5. If you do not want to display the prize list on the home page, uncheck 'Always Show Prize List' in the interface configuration.
|
||||||
|
6. When clicking buttons on the home page, the button value will not update immediately but will only update after the animation ends. This is a normal phenomenon.
|
||||||
|
|
||||||
|
## Shortcuts
|
||||||
|
|
||||||
|
Shortcuts are set up on the draw page.
|
||||||
|
|
||||||
|
| Shortcut | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| Space | Enter Draw / Start / Draw Lucky Winner / Continue |
|
||||||
|
| Esc | Cancel |
|
||||||
110
src/App.vue
110
src/App.vue
@@ -1,84 +1,90 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted,ref } from 'vue'
|
import PlayMusic from '@/components/PlayMusic/index.vue'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import PlayMusic from '@/components/PlayMusic/index.vue'
|
|
||||||
|
|
||||||
import { themeChange } from 'theme-change'
|
import { themeChange } from 'theme-change'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const prizeConfig = useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
const system=useStore().system
|
const system = useStore().system
|
||||||
const { getTheme: localTheme } = storeToRefs(globalConfig)
|
const { getTheme: localTheme } = storeToRefs(globalConfig)
|
||||||
const { getPrizeConfig: prizeList } = storeToRefs(prizeConfig)
|
const { getPrizeConfig: prizeList } = storeToRefs(prizeConfig)
|
||||||
// const { getIsMobile: isMobile } = storeToRefs(system)
|
|
||||||
|
|
||||||
const tipDialog=ref()
|
const tipDialog = ref()
|
||||||
// const isMobileValue = ref(structuredClone(isMobile.value))
|
// const isMobileValue = ref(structuredClone(isMobile.value))
|
||||||
const setLocalTheme = (theme: any) => {
|
function setLocalTheme(theme: any) {
|
||||||
themeChange(theme.name)
|
themeChange(theme.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 设置当前奖列表
|
// 设置当前奖列表
|
||||||
const setCurrentPrize = () => {
|
function setCurrentPrize() {
|
||||||
if (prizeList.value.length <= 0) {
|
if (prizeList.value.length <= 0) {
|
||||||
return
|
|
||||||
}
|
|
||||||
for (let i = 0; i < prizeList.value.length; i++) {
|
|
||||||
if (!prizeList.value[i].isUsed) {
|
|
||||||
prizeConfig.setCurrentPrize(prizeList.value[i])
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
}
|
||||||
|
for (let i = 0; i < prizeList.value.length; i++) {
|
||||||
|
if (!prizeList.value[i].isUsed) {
|
||||||
|
prizeConfig.setCurrentPrize(prizeList.value[i])
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 判断是否手机端访问
|
// 判断是否手机端访问
|
||||||
const judgeMobile=()=>{
|
function judgeMobile() {
|
||||||
const ua = navigator.userAgent
|
const ua = navigator.userAgent
|
||||||
const isAndroid = ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1
|
const isAndroid = ua.includes('Android') || ua.includes('Adr')
|
||||||
const isIOS =!!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
|
const isIOS = !!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
|
||||||
|
|
||||||
system.setIsMobile(isAndroid||isIOS)
|
system.setIsMobile(isAndroid || isIOS)
|
||||||
|
|
||||||
return isAndroid||isIOS
|
return isAndroid || isIOS
|
||||||
}
|
}
|
||||||
// 判断是否chrome或者edge访问
|
// 判断是否chrome或者edge访问
|
||||||
const judgeChromeOrEdge=()=>{
|
function judgeChromeOrEdge() {
|
||||||
const ua = navigator.userAgent
|
const ua = navigator.userAgent
|
||||||
const isChrome = ua.indexOf('Chrome') > -1
|
const isChrome = ua.includes('Chrome')
|
||||||
const isEdge = ua.indexOf('Edg') > -1
|
const isEdge = ua.includes('Edg')
|
||||||
|
|
||||||
system.setIsChrome(isChrome)
|
system.setIsChrome(isChrome)
|
||||||
|
|
||||||
return isChrome||isEdge
|
return isChrome || isEdge
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setLocalTheme(localTheme.value)
|
setLocalTheme(localTheme.value)
|
||||||
setCurrentPrize()
|
setCurrentPrize()
|
||||||
if(judgeMobile()||!judgeChromeOrEdge()){
|
if (judgeMobile() || !judgeChromeOrEdge()) {
|
||||||
tipDialog.value.showModal()
|
tipDialog.value.showModal()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<dialog id="my_modal_1" ref="tipDialog" class="border-none modal">
|
<dialog id="my_modal_1" ref="tipDialog" class="border-none modal">
|
||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<h3 class="text-lg font-bold">提示!</h3>
|
<h3 class="text-lg font-bold">
|
||||||
<p class="py-4" v-if="judgeMobile()">请使用PC进行访问以获得最佳显示效果</p>
|
{{ t('dialog.titleTip') }}
|
||||||
<p class="py-4" v-if=" !judgeChromeOrEdge()">请使用最新版Chrome或者Edge浏览器</p>
|
</h3>
|
||||||
<div class="modal-action">
|
<p v-if="judgeMobile()" class="py-4">
|
||||||
<form method="dialog" class="flex justify-start w-full gap-3">
|
{{ t('dialog.dialogPCWeb') }}
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
</p>
|
||||||
<button class="btn">确定</button>
|
<p v-if=" !judgeChromeOrEdge()" class="py-4">
|
||||||
</form>
|
{{ t('dialog.dialogLatestBrowser') }}
|
||||||
</div>
|
</p>
|
||||||
</div>
|
<div class="modal-action">
|
||||||
</dialog>
|
<form method="dialog" class="flex justify-start w-full gap-3">
|
||||||
<router-view></router-view>
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
<PlayMusic class="absolute right-0 bottom-1/2"></PlayMusic>
|
<button class="btn">
|
||||||
|
{{ t('button.confirm') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<router-view />
|
||||||
|
<PlayMusic class="absolute right-0 bottom-1/2" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@@ -1,61 +1,62 @@
|
|||||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig } from 'axios'
|
||||||
import type { InternalAxiosRequestConfig } from 'axios';
|
import axios from 'axios'
|
||||||
|
|
||||||
class Request {
|
class Request {
|
||||||
private instance: AxiosInstance;
|
private instance: AxiosInstance
|
||||||
|
|
||||||
constructor(config: AxiosRequestConfig) {
|
constructor(config: AxiosRequestConfig) {
|
||||||
this.instance = axios.create({
|
this.instance = axios.create({
|
||||||
baseURL: '/api',
|
baseURL: '/api',
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
...config,
|
...config,
|
||||||
});
|
})
|
||||||
|
|
||||||
// 添加请求拦截器
|
// 添加请求拦截器
|
||||||
this.instance.interceptors.request.use(
|
this.instance.interceptors.request.use(
|
||||||
(config: InternalAxiosRequestConfig) => {
|
(config: InternalAxiosRequestConfig) => {
|
||||||
// 在发送请求之前做些什么
|
// 在发送请求之前做些什么
|
||||||
console.log('请求拦截器被触发');
|
console.log('请求拦截器被触发')
|
||||||
|
|
||||||
return config;
|
return config
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
// 对请求错误做些什么
|
// 对请求错误做些什么
|
||||||
console.error('请求拦截器发生错误:', error);
|
console.error('请求拦截器发生错误:', error)
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error)
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
|
|
||||||
// 添加响应拦截器
|
// 添加响应拦截器
|
||||||
this.instance.interceptors.response.use(
|
this.instance.interceptors.response.use(
|
||||||
(response: AxiosResponse) => {
|
(response: AxiosResponse) => {
|
||||||
// 对响应数据做些什么
|
// 对响应数据做些什么
|
||||||
console.log('响应拦截器被触发');
|
console.log('响应拦截器被触发')
|
||||||
const reponseData = response.data;
|
const responseData = response.data
|
||||||
|
|
||||||
return reponseData;
|
return responseData
|
||||||
},
|
},
|
||||||
(error: any) => {
|
(error: any) => {
|
||||||
// 对响应错误做些什么
|
// 对响应错误做些什么
|
||||||
console.error('响应拦截器发生错误:', error);
|
console.error('响应拦截器发生错误:', error)
|
||||||
|
|
||||||
return Promise.reject(error);
|
return Promise.reject(error)
|
||||||
}
|
},
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public async request<T>(config: AxiosRequestConfig): Promise<T> {
|
public async request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||||
const response: AxiosResponse<T> = await this.instance.request(config);
|
const response: AxiosResponse<T> = await this.instance.request(config)
|
||||||
|
|
||||||
return response.data;
|
return response.data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 函数
|
// 函数
|
||||||
function request<T>(config: AxiosRequestConfig): Promise<T> {
|
function request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||||
const instance = new Request(config);
|
const instance = new Request(config)
|
||||||
|
|
||||||
return instance.request(config);
|
return instance.request(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default request;
|
export default request
|
||||||
|
|||||||
@@ -1,69 +1,78 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Array as any,
|
type: Array as any,
|
||||||
default: [] as any[]
|
default: [] as any[],
|
||||||
},
|
},
|
||||||
tableColumns: {
|
tableColumns: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: [] as any[]
|
default: [] as any[],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
const { t } = useI18n()
|
||||||
const dataColumns = computed<any[]>(() => {
|
const dataColumns = computed<any[]>(() => {
|
||||||
// 不带有actions的列
|
// 不带有actions的列
|
||||||
const columns = props.tableColumns.filter((item: any) => !item.actions)
|
const columns = props.tableColumns.filter((item: any) => !item.actions)
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
})
|
})
|
||||||
|
|
||||||
const actionsColumns = computed<any[]>(() => {
|
const actionsColumns = computed<any[]>(() => {
|
||||||
// 带有actions的列
|
// 带有actions的列
|
||||||
const columns = props.tableColumns.filter((item: any) => item.actions)
|
const columns = props.tableColumns.filter((item: any) => item.actions)
|
||||||
|
|
||||||
return columns
|
return columns
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table class="table min-w-[600px]">
|
<table class="table min-w-[600px]">
|
||||||
<!-- head -->
|
<!-- head -->
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th />
|
||||||
<th v-for="(item, index) in dataColumns" :key="index">{{ item.label }}</th>
|
<th v-for="(item, index) in dataColumns" :key="index">
|
||||||
<th v-for="(item, index) in actionsColumns" :key="index">操作</th>
|
{{ item.label }}
|
||||||
<th></th>
|
</th>
|
||||||
</tr>
|
<th v-for="(item, index) in actionsColumns" :key="index">
|
||||||
</thead>
|
{{ t('table.operation') }}
|
||||||
<tbody v-if="data.length > 0">
|
</th>
|
||||||
<!-- row -->
|
<th />
|
||||||
<tr class="hover" v-for="item in data" :key="item.id">
|
</tr>
|
||||||
<th>{{ item.id }}</th>
|
</thead>
|
||||||
<td v-for="(column, index) in dataColumns" :key="index">
|
<tbody v-if="data.length > 0">
|
||||||
<span v-if="column.formatValue">{{ column.formatValue(item) }}</span>
|
<!-- row -->
|
||||||
<span v-else>{{ item[column.props] }}</span>
|
<tr v-for="item in data" :key="item.id" class="hover">
|
||||||
</td>
|
<th>{{ item.id }}</th>
|
||||||
<!-- action -->
|
<td v-for="(column, index) in dataColumns" :key="index">
|
||||||
<td v-for="(column, index) in actionsColumns" :key="index" class="flex gap-2">
|
<span v-if="column.formatValue">{{ column.formatValue(item) }}</span>
|
||||||
<button class="btn btn-xs" v-for="action in column.actions" :key="action.name" :class="action.type"
|
<span v-else>{{ item[column.props] }}</span>
|
||||||
@click="action.onClick(item)">{{ action.label }}</button>
|
</td>
|
||||||
</td>
|
<!-- action -->
|
||||||
</tr>
|
<td v-for="(column, index) in actionsColumns" :key="index" class="flex gap-2">
|
||||||
</tbody>
|
<button
|
||||||
<tbody v-else>
|
v-for="action in column.actions" :key="action.name" class="btn btn-xs" :class="action.type"
|
||||||
<tr>
|
@click="action.onClick(item)"
|
||||||
<td colspan="5" class="text-center">暂无数据</td>
|
>
|
||||||
</tr>
|
{{ action.label }}
|
||||||
</tbody>
|
</button>
|
||||||
<!-- foot -->
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
<tbody v-else>
|
||||||
</div>
|
<tr>
|
||||||
|
<td colspan="5" class="text-center">
|
||||||
|
{{ t('table.noneData') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
<!-- foot -->
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue'
|
||||||
|
|
||||||
defineProps<{ msg: string }>();
|
defineProps<{ msg: string }>()
|
||||||
|
|
||||||
const count = ref(0);
|
const count = ref(0)
|
||||||
const addCount = () => {
|
function addCount() {
|
||||||
count.value++;
|
count.value++
|
||||||
};
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-4xl font-bold py-6">{{ msg }}</h1>
|
<h1 class="text-4xl font-bold py-6">
|
||||||
|
{{ msg }}
|
||||||
|
</h1>
|
||||||
|
|
||||||
<div class="card w-1200px">
|
<div class="card w-1200px">
|
||||||
<button
|
<button
|
||||||
@@ -29,16 +31,16 @@ const addCount = () => {
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
Check out
|
Check out
|
||||||
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
|
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank">create-vue</a>, the official Vue + Vite starter
|
||||||
>create-vue</a
|
|
||||||
>, the official Vue + Vite starter
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Install
|
Install
|
||||||
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
|
<a href="https://github.com/johnsoncodehk/volar" target="_blank">Volar</a>
|
||||||
in your IDE for a better DX
|
in your IDE for a better DX
|
||||||
</p>
|
</p>
|
||||||
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
|
<p class="read-the-docs">
|
||||||
|
Click on the Vite and Vue logos to learn more
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,41 +1,40 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import {ref,onMounted} from 'vue'
|
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
const props=defineProps({
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
imgItem: {
|
imgItem: {
|
||||||
type:Object,
|
type: Object,
|
||||||
default:()=>({})
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
const imageDbStore = localforage.createInstance({
|
const imageDbStore = localforage.createInstance({
|
||||||
name: 'imgStore'
|
name: 'imgStore',
|
||||||
})
|
})
|
||||||
|
|
||||||
const imgUrl=ref('')
|
const imgUrl = ref('')
|
||||||
|
|
||||||
|
async function getImageStoreItem(item: any): Promise<string> {
|
||||||
|
let image = ''
|
||||||
|
if (item.url === 'Storage') {
|
||||||
|
const key = item.id
|
||||||
|
image = await imageDbStore.getItem(key) as string
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
image = item.url
|
||||||
|
}
|
||||||
|
|
||||||
const getImageStoreItem=async (item:any):Promise<string>=>{
|
return image
|
||||||
let image=''
|
|
||||||
if(item.url=='Storage'){
|
|
||||||
const key=item.id;
|
|
||||||
image=await imageDbStore.getItem(key) as string
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
image=item.url
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return image
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(async ()=>{
|
onMounted(async () => {
|
||||||
const image=await getImageStoreItem(props.imgItem)
|
const image = await getImageStoreItem(props.imgItem)
|
||||||
imgUrl.value=image
|
imgUrl.value = image
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<img :src="imgUrl" alt="Image" class="object-cover h-full rounded-xl"/>
|
<img :src="imgUrl" alt="Image" class="object-cover h-full rounded-xl">
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -1,99 +1,111 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, watch, onMounted, toRefs } from 'vue'
|
import type { Separate } from '@/types/storeType'
|
||||||
import { Separate } from '@/types/storeType'
|
import { onMounted, ref, toRefs, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
totalNumber: {
|
totalNumber: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
separatedNumber: {
|
separatedNumber: {
|
||||||
type: Array<Separate>,
|
type: Array<Separate>,
|
||||||
default: []
|
default: [],
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const emits = defineEmits(['submitData'])
|
const emits = defineEmits(['submitData'])
|
||||||
|
const { t } = useI18n()
|
||||||
const separatedNumberRef = ref()
|
const separatedNumberRef = ref()
|
||||||
const { separatedNumber, totalNumber } = toRefs(props)
|
const { separatedNumber, totalNumber } = toRefs(props)
|
||||||
const scaleList = ref<number[]>([])
|
const scaleList = ref<number[]>([])
|
||||||
const editScale = (item: number) => {
|
function editScale(item: number) {
|
||||||
if (item == totalNumber.value) {
|
if (item === totalNumber.value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (scaleList.value.includes(item)) {
|
if (scaleList.value.includes(item)) {
|
||||||
const index = scaleList.value.indexOf(item)
|
const index = scaleList.value.indexOf(item)
|
||||||
scaleList.value.splice(index, 1)
|
scaleList.value.splice(index, 1)
|
||||||
separatedNumber.value.splice(index, 1)
|
separatedNumber.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scaleList.value.push(item)
|
scaleList.value.push(item)
|
||||||
scaleList.value.sort((a, b) => a - b)
|
scaleList.value.sort((a, b) => a - b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const clearData = () => {
|
function clearData() {
|
||||||
emits('submitData', separatedNumber.value)
|
emits('submitData', separatedNumber.value)
|
||||||
separatedNumberRef.value.close()
|
separatedNumberRef.value.close()
|
||||||
}
|
}
|
||||||
watch(scaleList, (val: number[]) => {
|
watch(scaleList, (val: number[]) => {
|
||||||
separatedNumber.value.length=0
|
separatedNumber.value.length = 0
|
||||||
for (let i = 1; i < scaleList.value.length; i++) {
|
for (let i = 1; i < scaleList.value.length; i++) {
|
||||||
separatedNumber.value[i - 1] = {
|
separatedNumber.value[i - 1] = {
|
||||||
id: i.toString(),
|
id: i.toString(),
|
||||||
count: val[i] - val[i - 1],
|
count: val[i] - val[i - 1],
|
||||||
isUsedCount: 0,
|
isUsedCount: 0,
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
watch(totalNumber, (val) => {
|
watch(totalNumber, (val) => {
|
||||||
if (val <= 0) {
|
if (val <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
separatedNumberRef.value.showModal()
|
separatedNumberRef.value.showModal()
|
||||||
// scaleList.value = [0, val]
|
// scaleList.value = [0, val]
|
||||||
scaleList.value = new Array(separatedNumber.value.length + 1).fill(totalNumber.value)
|
scaleList.value = Array.from({ length: separatedNumber.value.length + 1 }).fill(totalNumber.value) as number[]
|
||||||
for (let i = separatedNumber.value.length - 1; i >= 0; i--) {
|
for (let i = separatedNumber.value.length - 1; i >= 0; i--) {
|
||||||
scaleList.value[i] = scaleList.value[i + 1] - separatedNumber.value[i].count
|
scaleList.value[i] = scaleList.value[i + 1] - separatedNumber.value[i].count
|
||||||
}
|
}
|
||||||
if(scaleList.value[0]!==0){
|
if (scaleList.value[0] !== 0) {
|
||||||
scaleList.value.unshift(0)
|
scaleList.value.unshift(0)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 阻止esc事件
|
// 阻止esc事件
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if (e.key === 'Escape') {
|
if (e.key === 'Escape') {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<dialog id="my_modal_1" ref="separatedNumberRef" class="z-50 overflow-hidden border-none modal">
|
<dialog id="my_modal_1" ref="separatedNumberRef" class="z-50 overflow-hidden border-none modal">
|
||||||
<div class="overflow-hidden modal-box">
|
<div class="overflow-hidden modal-box">
|
||||||
<h3 class="pb-6 text-lg font-bold">提示!</h3>
|
<h3 class="pb-6 text-lg font-bold">
|
||||||
<p class="pb-8">单次抽取只能抽取10位</p>
|
{{ t('dialog.titleTip') }}
|
||||||
<div class="flex justify-between px-3 text-center separated-number">
|
</h3>
|
||||||
<div v-for="item in props.totalNumber" :key="item"
|
<p class="pb-8">
|
||||||
class="relative flex flex-col items-center cursor-pointer">
|
{{ t('dialog.dialogSingleDrawLimit') }}
|
||||||
<div class="absolute mb-12 text-center tooltip -top-5 hover:text-lg" data-tip="左键切割"
|
</p>
|
||||||
@click.left="editScale(item)">
|
<div class="flex justify-between px-3 text-center separated-number">
|
||||||
<span> {{ item }}</span>
|
<div
|
||||||
</div>
|
v-for="item in props.totalNumber" :key="item"
|
||||||
<div class="text-center" :class="scaleList.includes(item) ? 'text-red-500 font-extrabold' : ''">|</div>
|
class="relative flex flex-col items-center cursor-pointer"
|
||||||
</div>
|
>
|
||||||
</div>
|
<div
|
||||||
<div class="modal-action">
|
class="absolute mb-12 text-center tooltip -top-5 hover:text-lg" :data-tip="t('tooltip.leftClick')"
|
||||||
<form method="dialog">
|
@click.left="editScale(item)"
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
>
|
||||||
<button class="btn" @click="clearData">关闭</button>
|
<span> {{ item }}</span>
|
||||||
</form>
|
</div>
|
||||||
</div>
|
<div class="text-center" :class="scaleList.includes(item) ? 'text-red-500 font-extrabold' : ''">
|
||||||
|
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
</div>
|
||||||
|
<div class="modal-action">
|
||||||
|
<form method="dialog">
|
||||||
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
|
<button class="btn" @click="clearData">
|
||||||
|
{{ t('button.close') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,120 +1,127 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted, onUnmounted,watch } from 'vue'
|
import useStore from '@/store'
|
||||||
import useStore from '@/store';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const audioDbStore = localforage.createInstance({
|
const audioDbStore = localforage.createInstance({
|
||||||
name: 'audioStore'
|
name: 'audioStore',
|
||||||
})
|
})
|
||||||
const audio=ref(new Audio())
|
const audio = ref(new Audio())
|
||||||
const settingRef = ref()
|
const settingRef = ref()
|
||||||
// const audio = ref(new Audio())
|
// const audio = ref(new Audio())
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const { getMusicList: localMusicList,getCurrentMusic:currentMusic } = storeToRefs(globalConfig);
|
const { getMusicList: localMusicList, getCurrentMusic: currentMusic } = storeToRefs(globalConfig)
|
||||||
// const localMusicListValue = ref(localMusicList)
|
// const localMusicListValue = ref(localMusicList)
|
||||||
|
|
||||||
const play = async (item: any) => {
|
async function play(item: any) {
|
||||||
if(!item){
|
if (!item) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// if (!audio.value.paused && !skip) {
|
// if (!audio.value.paused && !skip) {
|
||||||
// audio.value.pause()
|
// audio.value.pause()
|
||||||
|
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
let audioUrl = ''
|
let audioUrl = ''
|
||||||
if (!item.url) {
|
if (!item.url) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (item.url == 'Storage') {
|
if (item.url === 'Storage') {
|
||||||
audioUrl = await audioDbStore.getItem(item.name) as string
|
audioUrl = await audioDbStore.getItem(item.name) as string
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
audioUrl = item.url
|
audioUrl = item.url
|
||||||
}
|
}
|
||||||
audio.value.pause()
|
audio.value.pause()
|
||||||
audio.value.src = audioUrl
|
audio.value.src = audioUrl
|
||||||
audio.value.play()
|
audio.value.play()
|
||||||
}
|
}
|
||||||
const playMusic=(item:any,skip = false)=>{
|
function playMusic(item: any, skip = false) {
|
||||||
if(!item){
|
if (!item) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(!currentMusic.value.paused&&!skip){
|
if (!currentMusic.value.paused && !skip) {
|
||||||
globalConfig.setCurrentMusic(item,true)
|
globalConfig.setCurrentMusic(item, true)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
globalConfig.setCurrentMusic(item,false)
|
globalConfig.setCurrentMusic(item, false)
|
||||||
}
|
}
|
||||||
const nextPlay = () => {
|
function nextPlay() {
|
||||||
// 播放下一首
|
// 播放下一首
|
||||||
if (localMusicList.value.length >= 1) {
|
if (localMusicList.value.length >= 1) {
|
||||||
let index = localMusicList.value.findIndex((item: any) => item.name == currentMusic.value.item.name)
|
let index = localMusicList.value.findIndex((item: any) => item.name === currentMusic.value.item.name)
|
||||||
index++
|
index++
|
||||||
if (index >= localMusicList.value.length) {
|
if (index >= localMusicList.value.length) {
|
||||||
index = 0
|
index = 0
|
||||||
}
|
|
||||||
globalConfig.setCurrentMusic(localMusicList.value[index],false)
|
|
||||||
}
|
}
|
||||||
|
globalConfig.setCurrentMusic(localMusicList.value[index], false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// 监听播放成后开始下一首
|
// 监听播放成后开始下一首
|
||||||
const onPlayEnd = () => {
|
function onPlayEnd() {
|
||||||
audio.value.addEventListener('ended', nextPlay)
|
audio.value.addEventListener('ended', nextPlay)
|
||||||
}
|
}
|
||||||
|
|
||||||
const enterConfig = () => {
|
function enterConfig() {
|
||||||
router.push('/log-lottery/config')
|
router.push('/log-lottery/config')
|
||||||
}
|
}
|
||||||
const enterHome = () => {
|
function enterHome() {
|
||||||
router.push('/log-lottery')
|
router.push('/log-lottery')
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
globalConfig.setCurrentMusic(localMusicList.value[0],true)
|
globalConfig.setCurrentMusic(localMusicList.value[0], true)
|
||||||
onPlayEnd()
|
onPlayEnd()
|
||||||
// 不使用空格控制audio
|
// 不使用空格控制audio
|
||||||
})
|
})
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
audio.value.removeEventListener('ended', nextPlay)
|
audio.value.removeEventListener('ended', nextPlay)
|
||||||
})
|
})
|
||||||
watch(currentMusic, (val: any) => {
|
watch(currentMusic, (val: any) => {
|
||||||
if(!val.paused&&audio.value){
|
if (!val.paused && audio.value) {
|
||||||
play(val.item)
|
play(val.item)
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
audio.value.pause()
|
audio.value.pause()
|
||||||
}
|
}
|
||||||
},{deep:true})
|
}, { deep: true })
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col gap-3" ref="settingRef">
|
<div ref="settingRef" class="flex flex-col gap-3">
|
||||||
<div v-if="route.path.includes('/config')" class="tooltip tooltip-left" data-tip="主页">
|
<div v-if="route.path.includes('/config')" class="tooltip tooltip-left" :data-tip="t('tooltip.toHome')">
|
||||||
<div class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
<div
|
||||||
@click="enterHome">
|
class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
||||||
<svg-icon name="home"></svg-icon>
|
@click="enterHome"
|
||||||
</div>
|
>
|
||||||
</div>
|
<svg-icon name="home" />
|
||||||
<div v-else class="tooltip tooltip-left" data-tip="设置/配置">
|
</div>
|
||||||
<div class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
|
||||||
@click="enterConfig">
|
|
||||||
<svg-icon name="setting"></svg-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="tooltip tooltip-left" :data-tip="currentMusic.item ? currentMusic.item.name+'\n\r 右键下一曲' : '没有音乐可以播放'">
|
|
||||||
<div class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
|
||||||
@click="playMusic(currentMusic.item)" @click.right.prevent="nextPlay">
|
|
||||||
<svg-icon :name="currentMusic.paused ? 'play' : 'pause'"></svg-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- <div class="bg-blue-300 cursor-pointer" @click="nextPlay">下一首</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else class="tooltip tooltip-left" :data-tip="t('tooltip.settingConfiguration')">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
||||||
|
@click="enterConfig"
|
||||||
|
>
|
||||||
|
<svg-icon name="setting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tooltip tooltip-left" :data-tip="currentMusic.item ? `${currentMusic.item.name}\n\r ${t('tooltip.nextSong')}` : t('tooltip.noSongPlay')">
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-center w-10 h-10 p-0 m-0 cursor-pointer setting-container bg-slate-500/50 rounded-l-xl hover:bg-slate-500/80 hover:text-blue-400/90"
|
||||||
|
@click="playMusic(currentMusic.item)" @click.right.prevent="nextPlay"
|
||||||
|
>
|
||||||
|
<svg-icon :name="currentMusic.paused ? 'play' : 'pause'" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ onMounted(() => {
|
|||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize', listenWindowSize)
|
window.removeEventListener('resize', listenWindowSize)
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
prefix: {
|
prefix: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -17,10 +18,11 @@ const props = defineProps({
|
|||||||
type: String,
|
type: String,
|
||||||
default: '24px',
|
default: '24px',
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
|
|
||||||
const symbolId = computed(() => `#${props.prefix}-${props.name}`);
|
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<svg
|
<svg
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
@@ -31,6 +33,7 @@ const symbolId = computed(() => `#${props.prefix}-${props.name}`);
|
|||||||
<use :xlink:href="symbolId" />
|
<use :xlink:href="symbolId" />
|
||||||
</svg>
|
</svg>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.svg-icon {
|
.svg-icon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
|||||||
@@ -3,9 +3,9 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="fixed z-50 flex items-center justify-center w-10 h-10 rounded-full shadow-lg cursor-pointer right-12 bottom-12 bg-slate-700 hover:bg-slate-600">
|
<div class="fixed z-50 flex items-center justify-center w-10 h-10 rounded-full shadow-lg cursor-pointer right-12 bottom-12 bg-slate-700 hover:bg-slate-600">
|
||||||
<svg-icon name="totop"></svg-icon>
|
<svg-icon name="toTop" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
export { default as Footer } from './Footer/index.vue'
|
||||||
/**
|
/**
|
||||||
*title: 自动导出组件
|
*title: 自动导出组件
|
||||||
*/
|
*/
|
||||||
export { default as Header } from './Header/index.vue';
|
export { default as Header } from './Header/index.vue'
|
||||||
export { default as Footer } from './Footer/index.vue';
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
|
import type { IPersonConfig } from '@/types/storeType'
|
||||||
import { rgba } from '@/utils/color'
|
import { rgba } from '@/utils/color'
|
||||||
import { IPersonConfig } from '@/types/storeType'
|
|
||||||
|
|
||||||
export const 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') => {
|
export const 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') => {
|
||||||
if (patternList.includes(index + 1) && mod == 'default') {
|
if (patternList.includes(index + 1) && mod == 'default') {
|
||||||
@@ -37,19 +37,19 @@ export const useElementStyle = (element: any, person: IPersonConfig, index: numb
|
|||||||
element.children[0].textContent = person.uid;
|
element.children[0].textContent = person.uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
element.children[1].style.fontSize = textSize + 'px'
|
element.children[1].style.fontSize = `${textSize}px`
|
||||||
element.children[1].style.lineHeight = textSize * 3 + 'px'
|
element.children[1].style.lineHeight = `${textSize * 3}px`
|
||||||
element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
|
element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
|
||||||
if (person.name) {
|
if (person.name) {
|
||||||
element.children[1].textContent = person.name
|
element.children[1].textContent = person.name
|
||||||
}
|
}
|
||||||
|
|
||||||
element.children[2].style.fontSize = textSize * 0.5 + 'px'
|
element.children[2].style.fontSize = `${textSize * 0.5}px`
|
||||||
if (person.department || person.identity) {
|
if (person.department || person.identity) {
|
||||||
element.children[2].innerHTML = `${person.department ? person.department : ''}<br/>${person.identity ? person.identity : ''}`
|
element.children[2].innerHTML = `${person.department ? person.department : ''}<br/>${person.identity ? person.identity : ''}`
|
||||||
}
|
}
|
||||||
|
|
||||||
return element
|
return element
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1704702652534" class="icon" viewBox="0 0 1025 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4194" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.1953125" height="200"><path d="M1013.64736 885.56544H11.13088c-6.12352 0-11.13088 5.00736-11.13088 11.14112v83.53792c0 6.12352 5.00736 11.14112 11.13088 11.14112h1002.50624c6.13376 0 11.14112-5.0176 11.14112-11.14112v-83.53792c0.01024-6.12352-4.99712-11.14112-11.13088-11.14112zM338.33984 253.00992h102.90176v471.04c0 6.12352 5.00736 11.14112 11.14112 11.14112h83.53792c6.12352 0 11.13088-5.0176 11.13088-11.14112v-471.04h103.17824c9.32864 0 14.47936-10.72128 8.76544-17.96096L503.06048 37.61152c-4.4544-5.71392-13.08672-5.71392-17.54112 0L329.5744 234.91584c-5.71392 7.3728-0.5632 18.09408 8.76544 18.09408z m0 0" p-id="4195"></path></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 1024 1024"><path fill="currentColor" d="M572.235 205.282v600.365a30.118 30.118 0 1 1-60.235 0V205.282L292.382 438.633a28.913 28.913 0 0 1-42.646 0a33.43 33.43 0 0 1 0-45.236l271.058-288.045a28.913 28.913 0 0 1 42.647 0L834.5 393.397a33.43 33.43 0 0 1 0 45.176a28.913 28.913 0 0 1-42.647 0l-219.618-233.23z"/></svg>
|
||||||
|
Before Width: | Height: | Size: 951 B After Width: | Height: | Size: 390 B |
@@ -7,4 +7,4 @@ export const footerList = {
|
|||||||
icon: 'github',
|
icon: 'github',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,19 +1,21 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { footerList } from './config';
|
import { footerList } from './config'
|
||||||
const skip = (url: string) => {
|
|
||||||
window.open(url);
|
function skip(url: string) {
|
||||||
};
|
window.open(url)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="footer-container">
|
<div class="footer-container">
|
||||||
<ul class="flex justify-center">
|
<ul class="flex justify-center">
|
||||||
<li
|
<li
|
||||||
v-for="item in footerList.data"
|
v-for="item in footerList.data"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
@click="skip(item.url)"
|
|
||||||
class="flex items-center gap-1 cursor-pointer"
|
class="flex items-center gap-1 cursor-pointer"
|
||||||
|
@click="skip(item.url)"
|
||||||
>
|
>
|
||||||
<svg-icon :name="item.icon"></svg-icon>
|
<svg-icon :name="item.icon" />
|
||||||
<p>{{ item.name }}</p>
|
<p>{{ item.name }}</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
export const navList = [
|
export const navList = [
|
||||||
{
|
{
|
||||||
id: 0,
|
id: 0,
|
||||||
name: '首页',
|
name: '首页',
|
||||||
url: 'home',
|
url: 'home',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: '项目',
|
name: '项目',
|
||||||
url: 'project',
|
url: 'project',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: '关于',
|
name: '关于',
|
||||||
url: 'about',
|
url: 'about',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,41 +1,52 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { navList } from './config';
|
import { navList } from './config'
|
||||||
const skip = (url: string) => {
|
|
||||||
window.open(url, '_self');
|
function skip(url: string) {
|
||||||
};
|
window.open(url, '_self')
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-full header-container">
|
<div class="h-full header-container">
|
||||||
<div class="p-0 navbar bg-base-100">
|
<div class="p-0 navbar bg-base-100">
|
||||||
<div class="navbar-start max-lg:w-full">
|
<div class="navbar-start max-lg:w-full">
|
||||||
<div class="dropdown">
|
<div class="dropdown">
|
||||||
<label tabindex="0" class="btn btn-ghost lg:hidden">
|
<label tabindex="0" class="btn btn-ghost lg:hidden">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24"
|
<svg
|
||||||
stroke="currentColor">
|
xmlns="http://www.w3.org/2000/svg" class="w-5 h-5" fill="none" viewBox="0 0 24 24"
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
stroke="currentColor"
|
||||||
d="M4 6h16M4 12h8m-8 6h16" />
|
>
|
||||||
</svg>
|
<path
|
||||||
</label>
|
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
<ul tabindex="0"
|
d="M4 6h16M4 12h8m-8 6h16"
|
||||||
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52 text-lg flex flex-col gap-2">
|
/>
|
||||||
<li class="cursor-pointer hover:text-gray-100 hover:bg-base-200" v-for="item in navList" :key="item.id" @click="skip(item.url)">{{ item.name }}</li>
|
</svg>
|
||||||
</ul>
|
</label>
|
||||||
</div>
|
<ul
|
||||||
<a class="text-xl lg:pl-12 max-lg:mx-auto" href="https://vitejs.dev" target="_blank">
|
tabindex="0"
|
||||||
<img src="/vite.svg" class="logo" alt="Vite logo" />
|
class="menu menu-sm dropdown-content mt-3 z-[1] p-2 shadow bg-base-100 rounded-box w-52 text-lg flex flex-col gap-2"
|
||||||
</a>
|
>
|
||||||
</div>
|
<li v-for="item in navList" :key="item.id" class="cursor-pointer hover:text-gray-100 hover:bg-base-200" @click="skip(item.url)">
|
||||||
<div class="hidden navbar-center lg:flex">
|
{{ item.name }}
|
||||||
<ul class="flex gap-10 px-1 text-lg cursor-pointer menu menu-horizontal">
|
</li>
|
||||||
<li class="hover:text-gray-100" v-for="item in navList" :key="item.id" @click="skip(item.url)">{{ item.name }}</li>
|
</ul>
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="navbar-end max-lg:w-0">
|
|
||||||
<a class="btn">Button</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
<a class="text-xl lg:pl-12 max-lg:mx-auto" href="https://vitejs.dev" target="_blank">
|
||||||
|
<img src="/vite.svg" class="logo" alt="Vite logo">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="hidden navbar-center lg:flex">
|
||||||
|
<ul class="flex gap-10 px-1 text-lg cursor-pointer menu menu-horizontal">
|
||||||
|
<li v-for="item in navList" :key="item.id" class="hover:text-gray-100" @click="skip(item.url)">
|
||||||
|
{{ item.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="navbar-end max-lg:w-0">
|
||||||
|
<a class="btn">Button</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss"></style>
|
<style scoped lang="scss"></style>
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// import Header from './Header/index.vue';
|
|
||||||
// import Footer from './Footer/index.vue';
|
|
||||||
import {ref} from 'vue';
|
|
||||||
import ToTop from '@/components/ToTop/index.vue'
|
import ToTop from '@/components/ToTop/index.vue'
|
||||||
import { useScroll } from '@vueuse/core'
|
import { useScroll } from '@vueuse/core'
|
||||||
|
// import Header from './Header/index.vue';
|
||||||
|
// import Footer from './Footer/index.vue';
|
||||||
|
import { ref } from 'vue'
|
||||||
|
|
||||||
const mainContainer = ref<HTMLElement | null>(null)
|
const mainContainer = ref<HTMLElement | null>(null)
|
||||||
|
|
||||||
const { y} = useScroll(mainContainer)
|
const { y } = useScroll(mainContainer)
|
||||||
|
|
||||||
const scrollToTop=()=>{
|
function scrollToTop() {
|
||||||
y.value=0
|
y.value = 0
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -19,16 +19,16 @@ const scrollToTop=()=>{
|
|||||||
<!-- <header class="shadow-2xl head-container h-14">
|
<!-- <header class="shadow-2xl head-container h-14">
|
||||||
<Header></Header>
|
<Header></Header>
|
||||||
</header> -->
|
</header> -->
|
||||||
<ToTop @click="scrollToTop" v-if="y>400"></ToTop>
|
<ToTop v-if="y > 400" @click="scrollToTop" />
|
||||||
<main ref="mainContainer" class="box-content w-screen h-screen overflow-x-hidden overflow-y-auto main-container">
|
<main ref="mainContainer" class="box-content w-screen h-screen overflow-x-hidden overflow-y-auto main-container">
|
||||||
<router-view class="h-full main-container-content"></router-view>
|
<router-view class="h-full main-container-content" />
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
<!-- <footer class="w-screen footer-container">
|
<!-- <footer class="w-screen footer-container">
|
||||||
<Footer></Footer>
|
<Footer></Footer>
|
||||||
</footer> -->
|
</footer> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
151
src/locales/en.ts
Normal file
151
src/locales/en.ts
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
export default {
|
||||||
|
button: {
|
||||||
|
enterLottery: 'Enter Lottery',
|
||||||
|
start: 'Start',
|
||||||
|
selectLucky: 'Draw the Lucky',
|
||||||
|
continue: 'Continue',
|
||||||
|
confirm: 'Confirm',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
setting: 'Setting',
|
||||||
|
delete: 'Delete',
|
||||||
|
allDelete: 'Delete All',
|
||||||
|
downloadTemplate: 'Download Template',
|
||||||
|
importData: 'Import Data',
|
||||||
|
resetData: 'Reset Data',
|
||||||
|
exportResult: 'Export Result',
|
||||||
|
add: 'Add',
|
||||||
|
resetDefault: 'Reset Default',
|
||||||
|
resetAllData: 'Reset All Data',
|
||||||
|
clearPattern: 'Clear Pattern',
|
||||||
|
DefaultPattern: 'Default Pattern',
|
||||||
|
upload: 'Upload',
|
||||||
|
reset: 'Reset',
|
||||||
|
play: 'Play',
|
||||||
|
setLayout: 'Set Layout',
|
||||||
|
close: 'Close',
|
||||||
|
noInfoAndImport: 'No Info and import it',
|
||||||
|
useDefault: 'Use Default Data',
|
||||||
|
},
|
||||||
|
sidebar: {
|
||||||
|
personConfiguration: 'Person Configuration',
|
||||||
|
personList: 'Person List',
|
||||||
|
winnerList: 'Winner List',
|
||||||
|
prizeConfiguration: 'Prize Configuration',
|
||||||
|
globalSetting: 'Global Configuration',
|
||||||
|
viewSetting: 'View Setting',
|
||||||
|
imagesManagement: 'Images Management',
|
||||||
|
musicManagement: 'Music Management',
|
||||||
|
operatingInstructions: 'Operating Instructions',
|
||||||
|
},
|
||||||
|
viewTitle: {
|
||||||
|
personManagement: 'Person Management',
|
||||||
|
winnerManagement: 'Winner Management',
|
||||||
|
prizeManagement: 'Prize Management',
|
||||||
|
globalSetting: 'Global Setting',
|
||||||
|
operatingInstructions: 'Operating Instructions',
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
// person configuration
|
||||||
|
number: 'Number',
|
||||||
|
name: 'Name',
|
||||||
|
prizeName: 'Name',
|
||||||
|
department: 'Department',
|
||||||
|
identity: 'Identity',
|
||||||
|
isLucky: 'Is Lucky',
|
||||||
|
operation: 'Operation',
|
||||||
|
setLuckyNumber: 'Set Lucky Number',
|
||||||
|
luckyPeopleNumber: 'Lucky People Number',
|
||||||
|
|
||||||
|
detail: 'Detail',
|
||||||
|
noneData: 'No Data',
|
||||||
|
// prize configuration
|
||||||
|
fullParticipation: 'FullParticipation',
|
||||||
|
numberParticipants: 'NumberParticipants',
|
||||||
|
isDone: 'is Done',
|
||||||
|
image: 'Image',
|
||||||
|
onceNumber: 'Once Number',
|
||||||
|
time: 'Time',
|
||||||
|
// view setting
|
||||||
|
title: 'Main Title',
|
||||||
|
columnNumber: 'Column Number',
|
||||||
|
theme: 'Theme',
|
||||||
|
language: 'Language',
|
||||||
|
cardColor: 'Card Color',
|
||||||
|
winnerColor: 'Winner Color',
|
||||||
|
textColor: 'Text Color',
|
||||||
|
cardWidth: 'Card Width',
|
||||||
|
cardHeight: 'Card Height',
|
||||||
|
textSize: 'Text Size',
|
||||||
|
highlightColor: 'HighLight Color',
|
||||||
|
patternSetting: 'Pattern Setting',
|
||||||
|
alwaysDisplay: 'Always Display Prize List',
|
||||||
|
selectPicture: 'Select a Picture',
|
||||||
|
backgroundImage: 'Select Background Image',
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
titleTip: 'Tip!',
|
||||||
|
titleTemporary: 'Add Temporary Activity',
|
||||||
|
dialogPCWeb: 'Please use a PC browser to access for optimal display performance',
|
||||||
|
dialogDelAllPerson: 'This operation will delete all personnel list data. Do you want to continue?',
|
||||||
|
dialogResetWinner: 'This operation will clear the winning information of personnel. Do you want to continue?',
|
||||||
|
dialogResetAllData: 'This operation will reset all data. Do you want to continue?',
|
||||||
|
dialogSingleDrawLimit: 'Only 10 characters can be extracted in a single draw',
|
||||||
|
dialogLatestBrowser: 'Please use the latest version of Chrome or Edge browser',
|
||||||
|
tipResetPrize: 'Performing operations may reset data, please proceed with caution',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
settingConfiguration: 'Setting/Configuration',
|
||||||
|
nextSong: 'Right Click to Next Song',
|
||||||
|
noSongPlay: 'No Song to Play',
|
||||||
|
prizeList: 'Prize List',
|
||||||
|
addActivity: 'Add Activity',
|
||||||
|
downloadTemplateTip: 'After downloading the file, please fill in the data in Excel and save it in xlsx format',
|
||||||
|
uploadExcelTip: 'Upload the modified Excel file',
|
||||||
|
leftClick: 'Left Click to Slice',
|
||||||
|
toHome: 'to Home',
|
||||||
|
resetLayout: 'This item is time-consuming and performance intensive',
|
||||||
|
defaultLayout: 'The default pattern setting is valid for 17 columns, please set the number of other columns yourself',
|
||||||
|
doneCount: 'Number of winners',
|
||||||
|
edit: 'Edit',
|
||||||
|
delete: 'Delete',
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
require: 'required field',
|
||||||
|
requireNumber: 'please enter a number',
|
||||||
|
minNumber1: 'the minimum is 1',
|
||||||
|
maxNumber100: 'the maximum is 100',
|
||||||
|
uploadSuccess: 'Upload Success',
|
||||||
|
uploadFail: 'Upload Failed',
|
||||||
|
notImage: 'Not Image',
|
||||||
|
personIsAllDone: 'All Person Is Done',
|
||||||
|
personNotEnough: 'Person Is Not Enough',
|
||||||
|
startDraw: 'Now Draw {count} {leftover} people',
|
||||||
|
completeInformation: 'Please provide complete information',
|
||||||
|
},
|
||||||
|
placeHolder: {
|
||||||
|
enterTitle: 'Enter Title',
|
||||||
|
name: 'Name',
|
||||||
|
winnerCount: 'Lucky Person Count',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
yes: 'Yes',
|
||||||
|
no: 'No',
|
||||||
|
number: 'Number',
|
||||||
|
isWin: 'isWin',
|
||||||
|
department: 'Department',
|
||||||
|
name: 'Name',
|
||||||
|
identity: 'Identity',
|
||||||
|
prizeName: 'Prize Name',
|
||||||
|
prizeTime: 'Prize Time',
|
||||||
|
operation: 'Operation',
|
||||||
|
delete: 'Delete',
|
||||||
|
removePerson: 'Remove the Person',
|
||||||
|
defaultTitle: 'The Prelude to the Six Ministries of the Ming Dynasty Cabinet',
|
||||||
|
xlsxName: 'personListTemplate-en.xlsx',
|
||||||
|
readmeName: 'readme-en.md',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'self-reflection': 'Turn inward and examine yourself when you encounter difficulties in life.',
|
||||||
|
'thiefEasy': 'Thief difficult mountain thief easily, breaking heart.',
|
||||||
|
},
|
||||||
|
}
|
||||||
32
src/locales/i18n.ts
Normal file
32
src/locales/i18n.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
// i18n配置
|
||||||
|
import { createI18n } from 'vue-i18n'
|
||||||
|
import en from './en'
|
||||||
|
import zhCn from './zhCn'
|
||||||
|
|
||||||
|
export type Language = 'en' | 'zhCn'
|
||||||
|
|
||||||
|
export const languageList = [
|
||||||
|
{
|
||||||
|
key: 'zhCn',
|
||||||
|
name: '中文',
|
||||||
|
flag: 'zh-cn',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'en',
|
||||||
|
name: 'English',
|
||||||
|
flag: 'en-us',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
export const browserLanguage = navigator.language.toLowerCase().includes('zh') ? 'zhCn' : 'en'
|
||||||
|
const globalConfig = JSON.parse(localStorage.getItem('globalConfig') || '{}').globalConfig || {}
|
||||||
|
// 创建i18n
|
||||||
|
const i18n = createI18n({
|
||||||
|
locale: globalConfig.language || browserLanguage,
|
||||||
|
legacy: false,
|
||||||
|
messages: {
|
||||||
|
zhCn,
|
||||||
|
en,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export default i18n
|
||||||
151
src/locales/zhCn.ts
Normal file
151
src/locales/zhCn.ts
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
export default {
|
||||||
|
button: {
|
||||||
|
enterLottery: '进入抽奖',
|
||||||
|
start: '开始',
|
||||||
|
selectLucky: '抽取幸运儿',
|
||||||
|
continue: '继续',
|
||||||
|
confirm: '确认',
|
||||||
|
cancel: '取消',
|
||||||
|
setting: '设置',
|
||||||
|
delete: '删除',
|
||||||
|
allDelete: '删除全部',
|
||||||
|
downloadTemplate: '下载模板',
|
||||||
|
importData: '导入数据',
|
||||||
|
resetData: '重置数据',
|
||||||
|
exportResult: '导出结果',
|
||||||
|
add: '添加',
|
||||||
|
resetDefault: '重置为默认',
|
||||||
|
resetAllData: '重置所有数据',
|
||||||
|
clearPattern: '清除图案',
|
||||||
|
DefaultPattern: '默认图案',
|
||||||
|
upload: '上传',
|
||||||
|
reset: '重置',
|
||||||
|
play: '播放',
|
||||||
|
setLayout: '重设布局',
|
||||||
|
close: '关闭',
|
||||||
|
noInfoAndImport: '暂无人员信息,前往导入',
|
||||||
|
useDefault: '使用默认数据',
|
||||||
|
},
|
||||||
|
sidebar: {
|
||||||
|
personConfiguration: '人员配置',
|
||||||
|
personList: '人员列表',
|
||||||
|
winnerList: '中奖人员',
|
||||||
|
prizeConfiguration: '奖品配置',
|
||||||
|
globalSetting: '全局配置',
|
||||||
|
viewSetting: '界面设置',
|
||||||
|
imagesManagement: '图片管理',
|
||||||
|
musicManagement: '音乐管理',
|
||||||
|
operatingInstructions: '操作说明',
|
||||||
|
},
|
||||||
|
viewTitle: {
|
||||||
|
personManagement: '人员管理',
|
||||||
|
winnerManagement: '已中奖人员管理',
|
||||||
|
prizeManagement: '奖项配置',
|
||||||
|
globalSetting: '全局配置',
|
||||||
|
operatingInstructions: '操作说明',
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
// person configuration
|
||||||
|
number: '编号',
|
||||||
|
name: '姓名',
|
||||||
|
prizeName: '名称',
|
||||||
|
department: '部门',
|
||||||
|
identity: '身份',
|
||||||
|
isLucky: '是否中奖',
|
||||||
|
operation: '操作',
|
||||||
|
setLuckyNumber: '设置中奖人数',
|
||||||
|
luckyPeopleNumber: '中奖人数',
|
||||||
|
|
||||||
|
detail: '详细信息',
|
||||||
|
noneData: '暂无数据',
|
||||||
|
// prize configuration
|
||||||
|
fullParticipation: '全员参加',
|
||||||
|
numberParticipants: '抽奖人数',
|
||||||
|
isDone: '已抽取',
|
||||||
|
image: '图片',
|
||||||
|
onceNumber: '单次抽取个数',
|
||||||
|
time: '时间',
|
||||||
|
// view setting
|
||||||
|
title: '主标题',
|
||||||
|
columnNumber: '列数',
|
||||||
|
theme: '主题',
|
||||||
|
language: '语言',
|
||||||
|
cardColor: '卡片颜色',
|
||||||
|
winnerColor: '中奖卡片颜色',
|
||||||
|
textColor: '文字颜色',
|
||||||
|
cardWidth: '卡片宽度',
|
||||||
|
cardHeight: '卡片高度',
|
||||||
|
textSize: '文字大小',
|
||||||
|
highlightColor: '高亮颜色',
|
||||||
|
patternSetting: '图案设置',
|
||||||
|
alwaysDisplay: '常显奖项列表',
|
||||||
|
selectPicture: '选择一张图片',
|
||||||
|
backgroundImage: '选择背景图片',
|
||||||
|
},
|
||||||
|
dialog: {
|
||||||
|
titleTip: '提示!',
|
||||||
|
titleTemporary: '增加临时抽奖',
|
||||||
|
dialogPCWeb: '请使用PC进行访问以获得最佳显示效果',
|
||||||
|
dialogDelAllPerson: '该操作会删除所有人员数据,是否继续?',
|
||||||
|
dialogResetWinner: '该操作会清空人员中奖信息,是否继续?',
|
||||||
|
dialogResetAllData: '该操作会重置所有数据,是否继续?',
|
||||||
|
dialogSingleDrawLimit: '单次抽取只能抽取10位',
|
||||||
|
dialogLatestBrowser: '请使用最新版Chrome或者Edge浏览器',
|
||||||
|
tipResetPrize: '进行操作可能会重置数据,请谨慎操作',
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
settingConfiguration: '设置/配置',
|
||||||
|
nextSong: '右键点击下一首',
|
||||||
|
noSongPlay: '没有音乐可以播放',
|
||||||
|
prizeList: '奖项列表',
|
||||||
|
addActivity: '添加抽奖',
|
||||||
|
downloadTemplateTip: '下载文件后,请在excel中填写数据,并保存为xlsx格式',
|
||||||
|
uploadExcelTip: '上传修改好的excel文件',
|
||||||
|
leftClick: '左键切割',
|
||||||
|
toHome: '主页',
|
||||||
|
resetLayout: '该项比较耗费时间和性能',
|
||||||
|
defaultLayout: '默认图案设置针对17列时有效,其他列数请自行设置',
|
||||||
|
doneCount: '已抽取',
|
||||||
|
edit: '编辑',
|
||||||
|
delete: '删除',
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
require: '必填项',
|
||||||
|
requireNumber: '请输入数字',
|
||||||
|
minNumber1: '最小为1',
|
||||||
|
maxNumber100: '最大为100',
|
||||||
|
uploadSuccess: '上传成功',
|
||||||
|
uploadFail: '上传失败',
|
||||||
|
notImage: '不是图片',
|
||||||
|
personIsAllDone: '抽奖抽完了',
|
||||||
|
personNotEnough: '抽奖人数不足',
|
||||||
|
startDraw: '现在抽取{count}{leftover}人',
|
||||||
|
completeInformation: '请填写完整信息',
|
||||||
|
},
|
||||||
|
placeHolder: {
|
||||||
|
enterTitle: '输入标题',
|
||||||
|
name: '名称',
|
||||||
|
winnerCount: '中奖人数',
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
yes: '是',
|
||||||
|
no: '否',
|
||||||
|
number: '编号',
|
||||||
|
isWin: '是否中奖',
|
||||||
|
department: '部门',
|
||||||
|
name: '姓名',
|
||||||
|
identity: '身份',
|
||||||
|
prizeName: '获奖',
|
||||||
|
prizeTime: '获奖时间',
|
||||||
|
operation: '操作',
|
||||||
|
delete: '删除',
|
||||||
|
removePerson: '移入未中奖名单',
|
||||||
|
defaultTitle: '大明内阁六部御前奏对',
|
||||||
|
xlsxName: '人口登记表-zhCn.xlsx',
|
||||||
|
readmeName: 'readme-zhCn.md',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'self-reflection': '行有不得,反求诸己',
|
||||||
|
'thiefEasy': '破山中贼易,破心中贼难',
|
||||||
|
},
|
||||||
|
}
|
||||||
35
src/main.ts
35
src/main.ts
@@ -1,24 +1,25 @@
|
|||||||
import { createApp } from 'vue';
|
import svgIcon from '@/components/SvgIcon/index.vue'
|
||||||
import './style.css';
|
import i18n from '@/locales/i18n'
|
||||||
|
import * as THREE from 'three'
|
||||||
|
import { createApp } from 'vue'
|
||||||
|
import VueDOMPurifyHTML from 'vue-dompurify-html'
|
||||||
|
import App from './App.vue'
|
||||||
|
import './style.css'
|
||||||
import './style/markdown.css'
|
import './style/markdown.css'
|
||||||
import './style/style.scss'
|
import './style/style.scss'
|
||||||
import * as THREE from 'three';
|
|
||||||
import App from './App.vue';
|
|
||||||
import VueDOMPurifyHTML from 'vue-dompurify-html'
|
|
||||||
|
|
||||||
const app = createApp(App);
|
|
||||||
// 全局svg组件
|
// 全局svg组件
|
||||||
import 'virtual:svg-icons-register';
|
import 'virtual:svg-icons-register'
|
||||||
import svgIcon from '@/components/SvgIcon/index.vue';
|
|
||||||
// svg全局组件// 路由
|
// svg全局组件// 路由
|
||||||
import router from '@/router';
|
import router from '@/router'
|
||||||
// pinia
|
// pinia
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from 'pinia'
|
||||||
// pinia持久化
|
// pinia持久化
|
||||||
import piniaPluginPersist from 'pinia-plugin-persist';
|
import piniaPluginPersist from 'pinia-plugin-persist'
|
||||||
const pinia = createPinia();
|
|
||||||
pinia.use(piniaPluginPersist);
|
|
||||||
|
|
||||||
app.config.globalProperties.$THREE = THREE; //挂载到原型
|
const app = createApp(App)
|
||||||
app.component('svg-icon', svgIcon);
|
const pinia = createPinia()
|
||||||
app.use(router).use(VueDOMPurifyHTML).use(pinia).mount('#app');
|
pinia.use(piniaPluginPersist)
|
||||||
|
|
||||||
|
app.config.globalProperties.$THREE = THREE // 挂载到原型
|
||||||
|
app.component('svg-icon', svgIcon)
|
||||||
|
app.use(router).use(VueDOMPurifyHTML).use(pinia).use(i18n).mount('#app')
|
||||||
|
|||||||
@@ -1,115 +1,117 @@
|
|||||||
import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router';
|
import Layout from '@/layout/index.vue'
|
||||||
import Layout from '@/layout/index.vue';
|
import i18n from '@/locales/i18n'
|
||||||
import Home from '@/views/Home/index.vue';
|
import Home from '@/views/Home/index.vue'
|
||||||
export const configRoutes={
|
import { createRouter, createWebHistory,createWebHashHistory } from 'vue-router'
|
||||||
path: '/log-lottery/config',
|
|
||||||
name: 'Config',
|
export const configRoutes = {
|
||||||
component: () => import('@/views/Config/index.vue'),
|
path: '/log-lottery/config',
|
||||||
children: [
|
name: 'Config',
|
||||||
|
component: () => import('@/views/Config/index.vue'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: '',
|
||||||
|
redirect: '/log-lottery/config/person',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/log-lottery/config/person',
|
||||||
|
name: 'PersonConfig',
|
||||||
|
component: () => import('@/views/Config/Person/PersonConfig.vue'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.global.t('sidebar.personConfiguration'),
|
||||||
|
icon: 'person',
|
||||||
|
},
|
||||||
|
children: [
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
redirect: '/log-lottery/config/person',
|
redirect: '/log-lottery/config/person/all',
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/log-lottery/config/person',
|
|
||||||
name: 'PersonConfig',
|
|
||||||
component: () => import('@/views/Config/Person/PersonConfig.vue'),
|
|
||||||
meta: {
|
|
||||||
title: '人员配置',
|
|
||||||
icon: 'person',
|
|
||||||
},
|
},
|
||||||
children:[
|
{
|
||||||
{
|
path: '/log-lottery/config/person/all',
|
||||||
path:'',
|
name: 'AllPersonConfig',
|
||||||
redirect: '/log-lottery/config/person/all',
|
component: () => import('@/views/Config/Person/PersonAll.vue'),
|
||||||
},
|
meta: {
|
||||||
{
|
title: i18n.global.t('sidebar.personList'),
|
||||||
path:'/log-lottery/config/person/all',
|
icon: 'all',
|
||||||
name:'AllPersonConfig',
|
},
|
||||||
component:()=>import('@/views/Config/Person/PersonAll.vue'),
|
|
||||||
meta:{
|
|
||||||
title:'人员名单',
|
|
||||||
icon:'all'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path:'/log-lottery/config/person/already',
|
|
||||||
name:'AlreadyPerson',
|
|
||||||
component:()=>import('@/views/Config/Person/PersonAlready.vue'),
|
|
||||||
meta:{
|
|
||||||
title:'中奖名单人员',
|
|
||||||
icon:'already'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// {
|
|
||||||
// path:'other',
|
|
||||||
// name:'OtherPersonConfig',
|
|
||||||
// component:()=>import('@/views/Config/Person/OtherPersonConfig.vue'),
|
|
||||||
// meta:{
|
|
||||||
// title:'其他配置',
|
|
||||||
// icon:'other'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: '/log-lottery/config/prize',
|
|
||||||
name: 'PrizeConfig',
|
|
||||||
component: () => import('@/views/Config/Prize/PrizeConfig.vue'),
|
|
||||||
meta:{
|
|
||||||
title: '奖品配置',
|
|
||||||
icon: 'prize'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path:'/log-lottery/config/global',
|
|
||||||
name:'GlobalConfig',
|
|
||||||
redirect: '/log-lottery/config/global/all',
|
|
||||||
meta:{
|
|
||||||
title:'全局配置',
|
|
||||||
icon:'global'
|
|
||||||
},
|
},
|
||||||
children:[
|
{
|
||||||
{
|
path: '/log-lottery/config/person/already',
|
||||||
path:'/log-lottery/config/global/face',
|
name: 'AlreadyPerson',
|
||||||
name:'FaceConfig',
|
component: () => import('@/views/Config/Person/PersonAlready.vue'),
|
||||||
component:()=>import('@/views/Config/Global/FaceConfig.vue'),
|
meta: {
|
||||||
meta:{
|
title: i18n.global.t('sidebar.winnerList'),
|
||||||
title:'界面配置',
|
icon: 'already',
|
||||||
icon:'face'
|
},
|
||||||
}
|
},
|
||||||
},
|
// {
|
||||||
{
|
// path:'other',
|
||||||
path:'/log-lottery/config/global/image',
|
// name:'OtherPersonConfig',
|
||||||
name:'ImageConfig',
|
// component:()=>import('@/views/Config/Person/OtherPersonConfig.vue'),
|
||||||
component:()=>import('@/views/Config/Global/ImageConfig.vue'),
|
// meta:{
|
||||||
meta:{
|
// title:'其他配置',
|
||||||
title:'图片列表',
|
// icon:'other'
|
||||||
icon:'image'
|
// }
|
||||||
}
|
// }
|
||||||
},
|
],
|
||||||
{
|
},
|
||||||
path:'/log-lottery/config/global/music',
|
{
|
||||||
name:'MusicConfig',
|
path: '/log-lottery/config/prize',
|
||||||
component:()=>import('@/views/Config/Global/MusicConfig.vue'),
|
name: 'PrizeConfig',
|
||||||
meta:{
|
component: () => import('@/views/Config/Prize/PrizeConfig.vue'),
|
||||||
title:'音乐列表',
|
meta: {
|
||||||
icon:'music'
|
title: i18n.global.t('sidebar.prizeConfiguration'),
|
||||||
}
|
icon: 'prize',
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
path: '/log-lottery/config/readme',
|
{
|
||||||
name: 'Readme',
|
path: '/log-lottery/config/global',
|
||||||
component: () => import('@/views/Config/Readme/index.vue'),
|
name: 'GlobalConfig',
|
||||||
meta:{
|
redirect: '/log-lottery/config/global/all',
|
||||||
title: '操作说明',
|
meta: {
|
||||||
icon: 'readme'
|
title: i18n.global.t('sidebar.globalSetting'),
|
||||||
}
|
icon: 'global',
|
||||||
},
|
},
|
||||||
]
|
children: [
|
||||||
}
|
{
|
||||||
|
path: '/log-lottery/config/global/face',
|
||||||
|
name: 'FaceConfig',
|
||||||
|
component: () => import('@/views/Config/Global/FaceConfig.vue'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.global.t('sidebar.viewSetting'),
|
||||||
|
icon: 'face',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/log-lottery/config/global/image',
|
||||||
|
name: 'ImageConfig',
|
||||||
|
component: () => import('@/views/Config/Global/ImageConfig.vue'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.global.t('sidebar.imagesManagement'),
|
||||||
|
icon: 'image',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/log-lottery/config/global/music',
|
||||||
|
name: 'MusicConfig',
|
||||||
|
component: () => import('@/views/Config/Global/MusicConfig.vue'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.global.t('sidebar.musicManagement'),
|
||||||
|
icon: 'music',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/log-lottery/config/readme',
|
||||||
|
name: 'Readme',
|
||||||
|
component: () => import('@/views/Config/Readme/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: i18n.global.t('sidebar.operatingInstructions'),
|
||||||
|
icon: 'readme',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
const routes = [
|
const routes = [
|
||||||
{
|
{
|
||||||
path: '/log-lottery',
|
path: '/log-lottery',
|
||||||
@@ -122,9 +124,9 @@ const routes = [
|
|||||||
component: Home,
|
component: Home,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path:'/log-lottery/demo',
|
path: '/log-lottery/demo',
|
||||||
name:'Demo',
|
name: 'Demo',
|
||||||
component:()=>import('@/views/Demo/index.vue')
|
component: () => import('@/views/Demo/index.vue'),
|
||||||
},
|
},
|
||||||
configRoutes,
|
configRoutes,
|
||||||
],
|
],
|
||||||
@@ -135,6 +137,6 @@ const router = createRouter({
|
|||||||
// 读取环境变量
|
// 读取环境变量
|
||||||
history: envMode==='file'?createWebHashHistory():createWebHistory(),
|
history: envMode==='file'?createWebHashHistory():createWebHistory(),
|
||||||
routes,
|
routes,
|
||||||
});
|
})
|
||||||
|
|
||||||
export default router;
|
export default router
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,258 +1,270 @@
|
|||||||
import { defineStore } from 'pinia';
|
import type { IImage, IMusic } from '@/types/storeType'
|
||||||
import { defaultMusicList, defaultImageList, defaultPatternList } from './data'
|
import i18n, { browserLanguage } from '@/locales/i18n'
|
||||||
import { IMusic, IImage } from '@/types/storeType';
|
import { defineStore } from 'pinia'
|
||||||
|
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,
|
||||||
topTitle: '大明内阁六部御前奏对',
|
topTitle: i18n.global.t('data.defaultTitle'),
|
||||||
theme: {
|
language: browserLanguage,
|
||||||
name: 'dracula',
|
theme: {
|
||||||
detail: { primary: '#0f5fd3' },
|
name: 'dracula',
|
||||||
cardColor: '#ff79c6',
|
detail: { primary: '#0f5fd3' },
|
||||||
cardWidth: 140,
|
cardColor: '#ff79c6',
|
||||||
cardHeight: 200,
|
cardWidth: 140,
|
||||||
textColor: '#ffffff',
|
cardHeight: 200,
|
||||||
luckyCardColor: '#ECB1AC',
|
textColor: '#ffffff',
|
||||||
textSize: 30,
|
luckyCardColor: '#ECB1AC',
|
||||||
patternColor: '#1b66c9',
|
textSize: 30,
|
||||||
patternList: defaultPatternList as number[],
|
patternColor: '#1b66c9',
|
||||||
background:{}, // 背景颜色或图片
|
patternList: defaultPatternList as number[],
|
||||||
},
|
background: {}, // 背景颜色或图片
|
||||||
musicList: defaultMusicList as IMusic[],
|
},
|
||||||
imageList: defaultImageList as IImage[],
|
musicList: defaultMusicList as IMusic[],
|
||||||
},
|
imageList: defaultImageList as IImage[],
|
||||||
currentMusic: {
|
},
|
||||||
item: defaultMusicList[0],
|
currentMusic: {
|
||||||
paused: true,
|
item: defaultMusicList[0],
|
||||||
},
|
paused: true,
|
||||||
};
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
// 获取全部配置
|
||||||
|
getGlobalConfig(state) {
|
||||||
|
return state.globalConfig
|
||||||
},
|
},
|
||||||
getters: {
|
// 获取标题
|
||||||
// 获取全部配置
|
getTopTitle(state) {
|
||||||
getGlobalConfig(state) {
|
return state.globalConfig.topTitle
|
||||||
return state.globalConfig;
|
|
||||||
},
|
|
||||||
// 获取标题
|
|
||||||
getTopTitle(state) {
|
|
||||||
return state.globalConfig.topTitle;
|
|
||||||
},
|
|
||||||
// 获取行数
|
|
||||||
getRowCount(state) {
|
|
||||||
return state.globalConfig.rowCount;
|
|
||||||
},
|
|
||||||
// 获取主题
|
|
||||||
getTheme(state) {
|
|
||||||
return state.globalConfig.theme;
|
|
||||||
},
|
|
||||||
// 获取卡片颜色
|
|
||||||
getCardColor(state) {
|
|
||||||
return state.globalConfig.theme.cardColor;
|
|
||||||
},
|
|
||||||
// 获取中奖颜色
|
|
||||||
getLuckyColor(state) {
|
|
||||||
return state.globalConfig.theme.luckyCardColor;
|
|
||||||
},
|
|
||||||
// 获取文字颜色
|
|
||||||
getTextColor(state) {
|
|
||||||
return state.globalConfig.theme.textColor;
|
|
||||||
},
|
|
||||||
// 获取卡片宽高
|
|
||||||
getCardSize(state) {
|
|
||||||
return {
|
|
||||||
width: state.globalConfig.theme.cardWidth,
|
|
||||||
height: state.globalConfig.theme.cardHeight
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 获取文字大小
|
|
||||||
getTextSize(state) {
|
|
||||||
return state.globalConfig.theme.textSize;
|
|
||||||
},
|
|
||||||
// 获取图案颜色
|
|
||||||
getPatterColor(state) {
|
|
||||||
return state.globalConfig.theme.patternColor;
|
|
||||||
},
|
|
||||||
// 获取图案列表
|
|
||||||
getPatternList(state) {
|
|
||||||
return state.globalConfig.theme.patternList;
|
|
||||||
},
|
|
||||||
// 获取音乐列表
|
|
||||||
getMusicList(state) {
|
|
||||||
return state.globalConfig.musicList;
|
|
||||||
},
|
|
||||||
// 获取当前音乐
|
|
||||||
getCurrentMusic(state) {
|
|
||||||
return state.currentMusic;
|
|
||||||
},
|
|
||||||
// 获取图片列表
|
|
||||||
getImageList(state) {
|
|
||||||
return state.globalConfig.imageList;
|
|
||||||
},
|
|
||||||
// 获取是否显示奖品列表
|
|
||||||
getIsShowPrizeList(state) {
|
|
||||||
return state.globalConfig.isSHowPrizeList;
|
|
||||||
},
|
|
||||||
// 获取背景图片设置
|
|
||||||
getBackground(state){
|
|
||||||
return state.globalConfig.theme.background
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
// 获取行数
|
||||||
// 设置rowCount
|
getRowCount(state) {
|
||||||
setRowCount(rowCount: number) {
|
return state.globalConfig.rowCount
|
||||||
this.globalConfig.rowCount = rowCount;
|
},
|
||||||
},
|
// 获取主题
|
||||||
// 设置标题
|
getTheme(state) {
|
||||||
setTopTitle(topTitle: string) {
|
return state.globalConfig.theme
|
||||||
this.globalConfig.topTitle = topTitle;
|
},
|
||||||
},
|
// 获取卡片颜色
|
||||||
// 设置主题
|
getCardColor(state) {
|
||||||
setTheme(theme: any) {
|
return state.globalConfig.theme.cardColor
|
||||||
const { name, detail } = theme;
|
},
|
||||||
this.globalConfig.theme.name = name;
|
// 获取中奖颜色
|
||||||
this.globalConfig.theme.detail = detail;
|
getLuckyColor(state) {
|
||||||
},
|
return state.globalConfig.theme.luckyCardColor
|
||||||
// 设置卡片颜色
|
},
|
||||||
setCardColor(cardColor: string) {
|
// 获取文字颜色
|
||||||
this.globalConfig.theme.cardColor = cardColor;
|
getTextColor(state) {
|
||||||
},
|
return state.globalConfig.theme.textColor
|
||||||
// 设置中奖颜色
|
},
|
||||||
setLuckyCardColor(luckyCardColor: string) {
|
// 获取卡片宽高
|
||||||
this.globalConfig.theme.luckyCardColor = luckyCardColor;
|
getCardSize(state) {
|
||||||
},
|
return {
|
||||||
// 设置文字颜色
|
width: state.globalConfig.theme.cardWidth,
|
||||||
setTextColor(textColor: string) {
|
height: state.globalConfig.theme.cardHeight,
|
||||||
this.globalConfig.theme.textColor = textColor;
|
}
|
||||||
},
|
},
|
||||||
// 设置卡片宽高
|
// 获取文字大小
|
||||||
setCardSize(cardSize: { width: number, height: number }) {
|
getTextSize(state) {
|
||||||
this.globalConfig.theme.cardWidth = cardSize.width;
|
return state.globalConfig.theme.textSize
|
||||||
this.globalConfig.theme.cardHeight = cardSize.height;
|
},
|
||||||
},
|
// 获取图案颜色
|
||||||
// 设置文字大小
|
getPatterColor(state) {
|
||||||
setTextSize(textSize: number) {
|
return state.globalConfig.theme.patternColor
|
||||||
this.globalConfig.theme.textSize = textSize;
|
},
|
||||||
},
|
// 获取图案列表
|
||||||
// 设置图案颜色
|
getPatternList(state) {
|
||||||
setPatterColor(patterColor: string) {
|
return state.globalConfig.theme.patternList
|
||||||
this.globalConfig.theme.patternColor = patterColor;
|
},
|
||||||
},
|
// 获取音乐列表
|
||||||
// 设置图案列表
|
getMusicList(state) {
|
||||||
setPatternList(patternList: number[]) {
|
return state.globalConfig.musicList
|
||||||
this.globalConfig.theme.patternList = patternList;
|
},
|
||||||
},
|
// 获取当前音乐
|
||||||
// 重置图案列表
|
getCurrentMusic(state) {
|
||||||
resetPatternList() {
|
return state.currentMusic
|
||||||
this.globalConfig.theme.patternList = defaultPatternList;
|
},
|
||||||
},
|
// 获取图片列表
|
||||||
// 添加音乐
|
getImageList(state) {
|
||||||
addMusic(music: IMusic) {
|
return state.globalConfig.imageList
|
||||||
// 验证音乐是否已存在,看name字段
|
},
|
||||||
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
// 获取是否显示奖品列表
|
||||||
if (this.globalConfig.musicList[i].name === music.name) {
|
getIsShowPrizeList(state) {
|
||||||
return;
|
return state.globalConfig.isSHowPrizeList
|
||||||
}
|
},
|
||||||
}
|
// 获取当前语言
|
||||||
this.globalConfig.musicList.push(music);
|
getLanguage(state) {
|
||||||
},
|
return state.globalConfig.language
|
||||||
// 删除音乐
|
},
|
||||||
removeMusic(musicId: string) {
|
// 获取背景图片设置
|
||||||
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
getBackground(state) {
|
||||||
if (this.globalConfig.musicList[i].id === musicId) {
|
return state.globalConfig.theme.background
|
||||||
this.globalConfig.musicList.splice(i, 1);
|
},
|
||||||
break;
|
},
|
||||||
}
|
actions: {
|
||||||
}
|
// 设置rowCount
|
||||||
},
|
setRowCount(rowCount: number) {
|
||||||
// 设置当前播放音乐
|
this.globalConfig.rowCount = rowCount
|
||||||
setCurrentMusic(musicItem: IMusic, paused: boolean = true) {
|
},
|
||||||
this.currentMusic = {
|
// 设置标题
|
||||||
item: musicItem,
|
setTopTitle(topTitle: string) {
|
||||||
paused: paused,
|
this.globalConfig.topTitle = topTitle
|
||||||
}
|
},
|
||||||
},
|
// 设置主题
|
||||||
// 重置音乐列表
|
setTheme(theme: any) {
|
||||||
resetMusicList() {
|
const { name, detail } = theme
|
||||||
this.globalConfig.musicList = defaultMusicList as IMusic[];
|
this.globalConfig.theme.name = name
|
||||||
},
|
this.globalConfig.theme.detail = detail
|
||||||
// 清空音乐列表
|
},
|
||||||
clearMusicList() {
|
// 设置卡片颜色
|
||||||
this.globalConfig.musicList = [] as IMusic[];
|
setCardColor(cardColor: string) {
|
||||||
},
|
this.globalConfig.theme.cardColor = cardColor
|
||||||
// 添加图片
|
},
|
||||||
addImage(image: IImage) {
|
// 设置中奖颜色
|
||||||
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
|
setLuckyCardColor(luckyCardColor: string) {
|
||||||
if (this.globalConfig.imageList[i].name === image.name) {
|
this.globalConfig.theme.luckyCardColor = luckyCardColor
|
||||||
return;
|
},
|
||||||
}
|
// 设置文字颜色
|
||||||
}
|
setTextColor(textColor: string) {
|
||||||
this.globalConfig.imageList.push(image);
|
this.globalConfig.theme.textColor = textColor
|
||||||
},
|
},
|
||||||
// 删除图片
|
// 设置卡片宽高
|
||||||
removeImage(imageId: string) {
|
setCardSize(cardSize: { width: number, height: number }) {
|
||||||
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
|
this.globalConfig.theme.cardWidth = cardSize.width
|
||||||
if (this.globalConfig.imageList[i].id === imageId) {
|
this.globalConfig.theme.cardHeight = cardSize.height
|
||||||
this.globalConfig.imageList.splice(i, 1);
|
},
|
||||||
break;
|
// 设置文字大小
|
||||||
}
|
setTextSize(textSize: number) {
|
||||||
}
|
this.globalConfig.theme.textSize = textSize
|
||||||
},
|
},
|
||||||
// 重置图片列表
|
// 设置图案颜色
|
||||||
resetImageList() {
|
setPatterColor(patterColor: string) {
|
||||||
this.globalConfig.imageList = defaultImageList as IImage[];
|
this.globalConfig.theme.patternColor = patterColor
|
||||||
},
|
},
|
||||||
// 清空图片列表
|
// 设置图案列表
|
||||||
clearImageList() {
|
setPatternList(patternList: number[]) {
|
||||||
this.globalConfig.imageList = [] as IImage[]
|
this.globalConfig.theme.patternList = patternList
|
||||||
},
|
},
|
||||||
// 设置是否显示奖品列表
|
// 重置图案列表
|
||||||
setIsShowPrizeList(isShowPrizeList: boolean) {
|
resetPatternList() {
|
||||||
this.globalConfig.isSHowPrizeList = isShowPrizeList;
|
this.globalConfig.theme.patternList = defaultPatternList
|
||||||
},
|
},
|
||||||
// 设置背景图片
|
// 添加音乐
|
||||||
setBackground(background:{}){
|
addMusic(music: IMusic) {
|
||||||
this.globalConfig.theme.background = background
|
// 验证音乐是否已存在,看name字段
|
||||||
},
|
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
||||||
// 重置所有配置
|
if (this.globalConfig.musicList[i].name === music.name) {
|
||||||
reset() {
|
return
|
||||||
this.globalConfig = {
|
|
||||||
rowCount: 17,
|
|
||||||
isSHowPrizeList: true,
|
|
||||||
topTitle: '大明内阁六部御前奏对',
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
this.globalConfig.musicList.push(music)
|
||||||
},
|
},
|
||||||
persist: {
|
// 删除音乐
|
||||||
enabled: true,
|
removeMusic(musicId: string) {
|
||||||
strategies: [
|
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
||||||
{
|
if (this.globalConfig.musicList[i].id === musicId) {
|
||||||
// 如果要存储在localStorage中
|
this.globalConfig.musicList.splice(i, 1)
|
||||||
storage: localStorage,
|
break
|
||||||
key: 'globalConfig',
|
}
|
||||||
paths: ['globalConfig'],
|
}
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
// 设置当前播放音乐
|
||||||
|
setCurrentMusic(musicItem: IMusic, paused: boolean = true) {
|
||||||
|
this.currentMusic = {
|
||||||
|
item: musicItem,
|
||||||
|
paused,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 重置音乐列表
|
||||||
|
resetMusicList() {
|
||||||
|
this.globalConfig.musicList = 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
|
||||||
|
},
|
||||||
|
// 重置所有配置
|
||||||
|
reset() {
|
||||||
|
this.globalConfig = {
|
||||||
|
rowCount: 17,
|
||||||
|
isSHowPrizeList: true,
|
||||||
|
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'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import {usePersonConfig} from './personConfig';
|
import { useGlobalConfig } from './globalConfig'
|
||||||
import { usePrizeConfig } from './prizeConfig';
|
import { usePersonConfig } from './personConfig'
|
||||||
import {useGlobalConfig} from './globalConfig';
|
import { usePrizeConfig } from './prizeConfig'
|
||||||
import {useSystem} from './system';
|
import { useSystem } from './system'
|
||||||
|
|
||||||
export default function useStore() {
|
export default function useStore() {
|
||||||
return {
|
return {
|
||||||
personConfig:usePersonConfig(),
|
personConfig: usePersonConfig(),
|
||||||
prizeConfig:usePrizeConfig(),
|
prizeConfig: usePrizeConfig(),
|
||||||
globalConfig:useGlobalConfig(),
|
globalConfig: useGlobalConfig(),
|
||||||
system:useSystem(),
|
system: useSystem(),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,158 +1,159 @@
|
|||||||
import { defineStore } from 'pinia';
|
import type { IPersonConfig, IPrizeConfig } from '@/types/storeType'
|
||||||
import { IPersonConfig } from '@/types/storeType';
|
|
||||||
import { IPrizeConfig } from '@/types/storeType';
|
|
||||||
import { defaultPersonList } from './data'
|
|
||||||
import { usePrizeConfig } from './prizeConfig';
|
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { defaultPersonList } from './data'
|
||||||
|
import { usePrizeConfig } from './prizeConfig'
|
||||||
|
|
||||||
export const usePersonConfig = defineStore('person', {
|
export const usePersonConfig = defineStore('person', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
personConfig: {
|
personConfig: {
|
||||||
allPersonList: [] as IPersonConfig[],
|
allPersonList: [] as IPersonConfig[],
|
||||||
alreadyPersonList: [] as IPersonConfig[],
|
alreadyPersonList: [] as IPersonConfig[],
|
||||||
}
|
},
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
// 获取全部配置
|
||||||
|
getPersonConfig(state) {
|
||||||
|
return state.personConfig
|
||||||
},
|
},
|
||||||
getters: {
|
// 获取全部人员名单
|
||||||
// 获取全部配置
|
getAllPersonList(state) {
|
||||||
getPersonConfig(state) {
|
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
||||||
return state.personConfig;
|
return item
|
||||||
},
|
})
|
||||||
// 获取全部人员名单
|
|
||||||
getAllPersonList(state) {
|
|
||||||
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
|
||||||
return item
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 获取未获此奖的人员名单
|
|
||||||
getNotThisPrizePersonList(state: any) {
|
|
||||||
const currentPrize = usePrizeConfig().prizeConfig.currentPrize;
|
|
||||||
const data = state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
|
||||||
return !item.prizeId.includes(currentPrize.id as string);
|
|
||||||
});
|
|
||||||
|
|
||||||
return data
|
|
||||||
},
|
|
||||||
// 获取已中奖人员名单
|
|
||||||
getAlreadyPersonList(state) {
|
|
||||||
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
|
||||||
return item.isWin === true;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 获取中奖人员详情
|
|
||||||
getAlreadyPersonDetail(state) {
|
|
||||||
return state.personConfig.alreadyPersonList
|
|
||||||
},
|
|
||||||
// 获取未中奖人员名单
|
|
||||||
getNotPersonList(state) {
|
|
||||||
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
|
||||||
return item.isWin === false;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
// 获取未获此奖的人员名单
|
||||||
// 添加未中奖人员
|
getNotThisPrizePersonList(state: any) {
|
||||||
addNotPersonList(personList: IPersonConfig[]) {
|
const currentPrize = usePrizeConfig().prizeConfig.currentPrize
|
||||||
if (personList.length <= 0) {
|
const data = state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
||||||
return
|
return !item.prizeId.includes(currentPrize.id as string)
|
||||||
}
|
})
|
||||||
personList.forEach((item: IPersonConfig) => {
|
|
||||||
this.personConfig.allPersonList.push(item);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 添加已中奖人员
|
|
||||||
addAlreadyPersonList(personList: IPersonConfig[], prize: IPrizeConfig | null) {
|
|
||||||
if (personList.length <= 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
personList.forEach((person: IPersonConfig) => {
|
|
||||||
this.personConfig.allPersonList.map((item: IPersonConfig) => {
|
|
||||||
if (item.id === person.id && prize != null) {
|
|
||||||
item.isWin = true
|
|
||||||
// person.isWin = true
|
|
||||||
item.prizeName.push(prize.name)
|
|
||||||
// person.prizeName += prize.name
|
|
||||||
item.prizeTime.push(dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'))
|
|
||||||
// person.prizeTime = new Date().toString()
|
|
||||||
item.prizeId.push(prize.id as string)
|
|
||||||
}
|
|
||||||
|
|
||||||
return item
|
return data
|
||||||
});
|
|
||||||
this.personConfig.alreadyPersonList.push(person);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// 从已中奖移动到未中奖
|
|
||||||
moveAlreadyToNot(person: IPersonConfig) {
|
|
||||||
if (person.id == undefined || person.id == null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const alreadyPersonListLength = this.personConfig.alreadyPersonList.length
|
|
||||||
for (let i = 0; i < this.personConfig.allPersonList.length; i++) {
|
|
||||||
if (person.id === this.personConfig.allPersonList[i].id) {
|
|
||||||
this.personConfig.allPersonList[i].isWin = false
|
|
||||||
this.personConfig.allPersonList[i].prizeName = []
|
|
||||||
this.personConfig.allPersonList[i].prizeTime = []
|
|
||||||
this.personConfig.allPersonList[i].prizeId = []
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (let i = 0; i < alreadyPersonListLength; i++) {
|
|
||||||
this.personConfig.alreadyPersonList = this.personConfig.alreadyPersonList.filter((item: IPersonConfig) =>
|
|
||||||
item.id !== person.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 删除指定人员
|
|
||||||
deletePerson(person: IPersonConfig) {
|
|
||||||
if (person.id != undefined || person.id != null) {
|
|
||||||
this.personConfig.allPersonList = this.personConfig.allPersonList.filter((item: IPersonConfig) => item.id !== person.id);
|
|
||||||
this.personConfig.alreadyPersonList = this.personConfig.alreadyPersonList.filter((item: IPersonConfig) => item.id !== person.id);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 删除所有人员
|
|
||||||
deleteAllPerson() {
|
|
||||||
this.personConfig.allPersonList = [];
|
|
||||||
this.personConfig.alreadyPersonList = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
// 删除所有人员
|
|
||||||
resetPerson() {
|
|
||||||
this.personConfig.allPersonList = [];
|
|
||||||
this.personConfig.alreadyPersonList = [];
|
|
||||||
},
|
|
||||||
// 重置已中奖人员
|
|
||||||
resetAlreadyPerson() {
|
|
||||||
// 把已中奖人员合并到未中奖人员,要验证是否已存在
|
|
||||||
this.personConfig.allPersonList.forEach((item: IPersonConfig) => {
|
|
||||||
item.isWin = false;
|
|
||||||
item.prizeName = [];
|
|
||||||
item.prizeTime = [];
|
|
||||||
item.prizeId = []
|
|
||||||
});
|
|
||||||
this.personConfig.alreadyPersonList = [];
|
|
||||||
},
|
|
||||||
setDefaultPersonList() {
|
|
||||||
this.personConfig.allPersonList = defaultPersonList;
|
|
||||||
this.personConfig.alreadyPersonList = [];
|
|
||||||
},
|
|
||||||
// 重置所有配置
|
|
||||||
reset() {
|
|
||||||
this.personConfig = {
|
|
||||||
allPersonList: [] as IPersonConfig[],
|
|
||||||
alreadyPersonList: [] as IPersonConfig[],
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
persist: {
|
// 获取已中奖人员名单
|
||||||
enabled: true,
|
getAlreadyPersonList(state) {
|
||||||
strategies: [
|
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
||||||
{
|
return item.isWin === true
|
||||||
// 如果要存储在localStorage中
|
})
|
||||||
storage: localStorage,
|
|
||||||
key: 'personConfig',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
// 获取中奖人员详情
|
||||||
|
getAlreadyPersonDetail(state) {
|
||||||
|
return state.personConfig.alreadyPersonList
|
||||||
|
},
|
||||||
|
// 获取未中奖人员名单
|
||||||
|
getNotPersonList(state) {
|
||||||
|
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
||||||
|
return item.isWin === false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
// 添加未中奖人员
|
||||||
|
addNotPersonList(personList: IPersonConfig[]) {
|
||||||
|
if (personList.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
personList.forEach((item: IPersonConfig) => {
|
||||||
|
this.personConfig.allPersonList.push(item)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 添加已中奖人员
|
||||||
|
addAlreadyPersonList(personList: IPersonConfig[], prize: IPrizeConfig | null) {
|
||||||
|
if (personList.length <= 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
personList.forEach((person: IPersonConfig) => {
|
||||||
|
this.personConfig.allPersonList.map((item: IPersonConfig) => {
|
||||||
|
if (item.id === person.id && prize != null) {
|
||||||
|
item.isWin = true
|
||||||
|
// person.isWin = true
|
||||||
|
item.prizeName.push(prize.name)
|
||||||
|
// person.prizeName += prize.name
|
||||||
|
item.prizeTime.push(dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'))
|
||||||
|
// person.prizeTime = new Date().toString()
|
||||||
|
item.prizeId.push(prize.id as string)
|
||||||
|
}
|
||||||
|
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
this.personConfig.alreadyPersonList.push(person)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 从已中奖移动到未中奖
|
||||||
|
moveAlreadyToNot(person: IPersonConfig) {
|
||||||
|
if (person.id === undefined || person.id == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const alreadyPersonListLength = this.personConfig.alreadyPersonList.length
|
||||||
|
for (let i = 0; i < this.personConfig.allPersonList.length; i++) {
|
||||||
|
if (person.id === this.personConfig.allPersonList[i].id) {
|
||||||
|
this.personConfig.allPersonList[i].isWin = false
|
||||||
|
this.personConfig.allPersonList[i].prizeName = []
|
||||||
|
this.personConfig.allPersonList[i].prizeTime = []
|
||||||
|
this.personConfig.allPersonList[i].prizeId = []
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let i = 0; i < alreadyPersonListLength; i++) {
|
||||||
|
this.personConfig.alreadyPersonList = this.personConfig.alreadyPersonList.filter((item: IPersonConfig) =>
|
||||||
|
item.id !== person.id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除指定人员
|
||||||
|
deletePerson(person: IPersonConfig) {
|
||||||
|
if (person.id !== undefined || person.id != null) {
|
||||||
|
this.personConfig.allPersonList = this.personConfig.allPersonList.filter((item: IPersonConfig) => item.id !== person.id)
|
||||||
|
this.personConfig.alreadyPersonList = this.personConfig.alreadyPersonList.filter((item: IPersonConfig) => item.id !== person.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 删除所有人员
|
||||||
|
deleteAllPerson() {
|
||||||
|
this.personConfig.allPersonList = []
|
||||||
|
this.personConfig.alreadyPersonList = []
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除所有人员
|
||||||
|
resetPerson() {
|
||||||
|
this.personConfig.allPersonList = []
|
||||||
|
this.personConfig.alreadyPersonList = []
|
||||||
|
},
|
||||||
|
// 重置已中奖人员
|
||||||
|
resetAlreadyPerson() {
|
||||||
|
// 把已中奖人员合并到未中奖人员,要验证是否已存在
|
||||||
|
this.personConfig.allPersonList.forEach((item: IPersonConfig) => {
|
||||||
|
item.isWin = false
|
||||||
|
item.prizeName = []
|
||||||
|
item.prizeTime = []
|
||||||
|
item.prizeId = []
|
||||||
|
})
|
||||||
|
this.personConfig.alreadyPersonList = []
|
||||||
|
},
|
||||||
|
setDefaultPersonList() {
|
||||||
|
this.personConfig.allPersonList = defaultPersonList
|
||||||
|
this.personConfig.alreadyPersonList = []
|
||||||
|
},
|
||||||
|
// 重置所有配置
|
||||||
|
reset() {
|
||||||
|
this.personConfig = {
|
||||||
|
allPersonList: [] as IPersonConfig[],
|
||||||
|
alreadyPersonList: [] as IPersonConfig[],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
persist: {
|
||||||
|
enabled: true,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
// 如果要存储在localStorage中
|
||||||
|
storage: localStorage,
|
||||||
|
key: 'personConfig',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,176 +1,177 @@
|
|||||||
import { defineStore } from 'pinia';
|
import type { IPrizeConfig } from '@/types/storeType'
|
||||||
import { IPrizeConfig } from '@/types/storeType';
|
import { defineStore } from 'pinia'
|
||||||
import { defaultPrizeList, defaultCurrentPrize } from './data';
|
import { defaultCurrentPrize, defaultPrizeList } from './data'
|
||||||
|
|
||||||
export const usePrizeConfig = defineStore('prize', {
|
export const usePrizeConfig = defineStore('prize', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
prizeConfig: {
|
prizeConfig: {
|
||||||
prizeList: defaultPrizeList,
|
prizeList: defaultPrizeList,
|
||||||
currentPrize: defaultCurrentPrize,
|
currentPrize: defaultCurrentPrize,
|
||||||
temporaryPrize: {
|
temporaryPrize: {
|
||||||
id: '',
|
id: '',
|
||||||
name: '',
|
name: '',
|
||||||
sort: 0,
|
sort: 0,
|
||||||
isAll: false,
|
isAll: false,
|
||||||
count: 1,
|
count: 1,
|
||||||
isUsedCount: 0,
|
isUsedCount: 0,
|
||||||
picture: {
|
picture: {
|
||||||
id: '-1',
|
id: '-1',
|
||||||
name: '',
|
name: '',
|
||||||
url: ''
|
url: '',
|
||||||
},
|
},
|
||||||
separateCount: {
|
separateCount: {
|
||||||
enable: true,
|
enable: true,
|
||||||
countList: []
|
countList: [],
|
||||||
},
|
},
|
||||||
desc: '',
|
desc: '',
|
||||||
isShow: false,
|
isShow: false,
|
||||||
isUsed: false,
|
isUsed: false,
|
||||||
frequency: 1,
|
frequency: 1,
|
||||||
} as IPrizeConfig
|
} as IPrizeConfig,
|
||||||
}
|
},
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
// 获取全部配置
|
||||||
|
getPrizeConfigAll(state) {
|
||||||
|
return state.prizeConfig
|
||||||
},
|
},
|
||||||
getters: {
|
// 获取奖品列表
|
||||||
// 获取全部配置
|
getPrizeConfig(state) {
|
||||||
getPrizeConfigAll(state) {
|
return state.prizeConfig.prizeList
|
||||||
return state.prizeConfig;
|
},
|
||||||
},
|
// 根据id获取配置
|
||||||
// 获取奖品列表
|
getPrizeConfigById(state) {
|
||||||
getPrizeConfig(state) {
|
return (id: number | string) => {
|
||||||
return state.prizeConfig.prizeList;
|
return state.prizeConfig.prizeList.find(item => item.id === id)
|
||||||
},
|
}
|
||||||
// 根据id获取配置
|
},
|
||||||
getPrizeConfigById(state) {
|
// 获取当前奖项
|
||||||
return (id: number | string) => {
|
getCurrentPrize(state) {
|
||||||
return state.prizeConfig.prizeList.find(item => item.id === id);
|
return state.prizeConfig.currentPrize
|
||||||
}
|
},
|
||||||
},
|
// 获取临时的奖项
|
||||||
// 获取当前奖项
|
getTemporaryPrize(state) {
|
||||||
getCurrentPrize(state) {
|
return state.prizeConfig.temporaryPrize
|
||||||
return state.prizeConfig.currentPrize;
|
|
||||||
},
|
|
||||||
// 获取临时的奖项
|
|
||||||
getTemporaryPrize(state) {
|
|
||||||
return state.prizeConfig.temporaryPrize;
|
|
||||||
},
|
|
||||||
|
|
||||||
},
|
},
|
||||||
actions: {
|
|
||||||
// 设置奖项
|
|
||||||
setPrizeConfig(prizeList: IPrizeConfig[]) {
|
|
||||||
this.prizeConfig.prizeList = prizeList;
|
|
||||||
},
|
|
||||||
// 添加奖项
|
|
||||||
addPrizeConfig(prizeConfigItem: IPrizeConfig) {
|
|
||||||
this.prizeConfig.prizeList.push(prizeConfigItem);
|
|
||||||
},
|
|
||||||
// 删除奖项
|
|
||||||
deletePrizeConfig(prizeConfigItemId: number | string) {
|
|
||||||
this.prizeConfig.prizeList = this.prizeConfig.prizeList.filter(item => item.id !== prizeConfigItemId);
|
|
||||||
},
|
|
||||||
// 更新奖项数据
|
|
||||||
updatePrizeConfig(prizeConfigItem: IPrizeConfig) {
|
|
||||||
const prizeListLength = this.prizeConfig.prizeList.length;
|
|
||||||
if (prizeConfigItem.isUsed && prizeListLength) {
|
|
||||||
for (let i = 0; i < prizeListLength; i++) {
|
|
||||||
if (!this.prizeConfig.prizeList[i].isUsed) {
|
|
||||||
this.setCurrentPrize(this.prizeConfig.prizeList[i]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.resetTemporaryPrize()
|
|
||||||
},
|
|
||||||
// 删除全部奖项
|
|
||||||
deleteAllPrizeConfig() {
|
|
||||||
this.prizeConfig.prizeList = [] as IPrizeConfig[];
|
|
||||||
},
|
|
||||||
// 设置当前奖项
|
|
||||||
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
|
||||||
this.prizeConfig.currentPrize = prizeConfigItem
|
|
||||||
},
|
|
||||||
// 设置临时奖项
|
|
||||||
setTemporaryPrize(prizeItem: IPrizeConfig) {
|
|
||||||
if (prizeItem.isShow == false) {
|
|
||||||
for (let i = 0; i < this.prizeConfig.prizeList.length; i++) {
|
|
||||||
if (this.prizeConfig.prizeList[i].isUsed == false) {
|
|
||||||
this.setCurrentPrize(this.prizeConfig.prizeList[i]);
|
|
||||||
|
|
||||||
break
|
},
|
||||||
}
|
actions: {
|
||||||
}
|
// 设置奖项
|
||||||
this.resetTemporaryPrize()
|
setPrizeConfig(prizeList: IPrizeConfig[]) {
|
||||||
|
this.prizeConfig.prizeList = prizeList
|
||||||
return
|
},
|
||||||
}
|
// 添加奖项
|
||||||
|
addPrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||||
this.prizeConfig.temporaryPrize = prizeItem
|
this.prizeConfig.prizeList.push(prizeConfigItem)
|
||||||
},
|
},
|
||||||
// 重置临时奖项
|
// 删除奖项
|
||||||
resetTemporaryPrize() {
|
deletePrizeConfig(prizeConfigItemId: number | string) {
|
||||||
this.prizeConfig.temporaryPrize = {
|
this.prizeConfig.prizeList = this.prizeConfig.prizeList.filter(item => item.id !== prizeConfigItemId)
|
||||||
id: '',
|
},
|
||||||
name: '',
|
// 更新奖项数据
|
||||||
sort: 0,
|
updatePrizeConfig(prizeConfigItem: IPrizeConfig) {
|
||||||
isAll: false,
|
const prizeListLength = this.prizeConfig.prizeList.length
|
||||||
count: 1,
|
if (prizeConfigItem.isUsed && prizeListLength) {
|
||||||
isUsedCount: 0,
|
for (let i = 0; i < prizeListLength; i++) {
|
||||||
picture: {
|
if (!this.prizeConfig.prizeList[i].isUsed) {
|
||||||
id: '-1',
|
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||||
name: '',
|
break
|
||||||
url: ''
|
}
|
||||||
},
|
|
||||||
separateCount: {
|
|
||||||
enable: true,
|
|
||||||
countList: []
|
|
||||||
},
|
|
||||||
desc: '',
|
|
||||||
isShow: false,
|
|
||||||
isUsed: false,
|
|
||||||
frequency: 1,
|
|
||||||
} as IPrizeConfig;
|
|
||||||
},
|
|
||||||
// 重置所有配置
|
|
||||||
resetDefault() {
|
|
||||||
this.prizeConfig = {
|
|
||||||
prizeList: defaultPrizeList,
|
|
||||||
currentPrize: defaultCurrentPrize,
|
|
||||||
temporaryPrize: {
|
|
||||||
id: '',
|
|
||||||
name: '',
|
|
||||||
sort: 0,
|
|
||||||
isAll: false,
|
|
||||||
count: 1,
|
|
||||||
isUsedCount: 0,
|
|
||||||
picture: {
|
|
||||||
id: '-1',
|
|
||||||
name: '',
|
|
||||||
url: ''
|
|
||||||
},
|
|
||||||
separateCount: {
|
|
||||||
enable: true,
|
|
||||||
countList: []
|
|
||||||
},
|
|
||||||
desc: '',
|
|
||||||
isShow: false,
|
|
||||||
isUsed: false,
|
|
||||||
frequency: 1,
|
|
||||||
} as IPrizeConfig
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resetTemporaryPrize()
|
||||||
},
|
},
|
||||||
persist: {
|
// 删除全部奖项
|
||||||
enabled: true,
|
deleteAllPrizeConfig() {
|
||||||
strategies: [
|
this.prizeConfig.prizeList = [] as IPrizeConfig[]
|
||||||
{
|
|
||||||
// 如果要存储在localStorage中
|
|
||||||
storage: localStorage,
|
|
||||||
key: 'prizeConfig',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
});
|
// 设置当前奖项
|
||||||
|
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
||||||
|
this.prizeConfig.currentPrize = prizeConfigItem
|
||||||
|
},
|
||||||
|
// 设置临时奖项
|
||||||
|
setTemporaryPrize(prizeItem: IPrizeConfig) {
|
||||||
|
if (prizeItem.isShow === false) {
|
||||||
|
for (let i = 0; i < this.prizeConfig.prizeList.length; i++) {
|
||||||
|
if (this.prizeConfig.prizeList[i].isUsed === false) {
|
||||||
|
this.setCurrentPrize(this.prizeConfig.prizeList[i])
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.resetTemporaryPrize()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prizeConfig.temporaryPrize = prizeItem
|
||||||
|
},
|
||||||
|
// 重置临时奖项
|
||||||
|
resetTemporaryPrize() {
|
||||||
|
this.prizeConfig.temporaryPrize = {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
sort: 0,
|
||||||
|
isAll: false,
|
||||||
|
count: 1,
|
||||||
|
isUsedCount: 0,
|
||||||
|
picture: {
|
||||||
|
id: '-1',
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
separateCount: {
|
||||||
|
enable: true,
|
||||||
|
countList: [],
|
||||||
|
},
|
||||||
|
desc: '',
|
||||||
|
isShow: false,
|
||||||
|
isUsed: false,
|
||||||
|
frequency: 1,
|
||||||
|
} as IPrizeConfig
|
||||||
|
},
|
||||||
|
// 重置所有配置
|
||||||
|
resetDefault() {
|
||||||
|
this.prizeConfig = {
|
||||||
|
prizeList: defaultPrizeList,
|
||||||
|
currentPrize: defaultCurrentPrize,
|
||||||
|
temporaryPrize: {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
sort: 0,
|
||||||
|
isAll: false,
|
||||||
|
count: 1,
|
||||||
|
isUsedCount: 0,
|
||||||
|
picture: {
|
||||||
|
id: '-1',
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
separateCount: {
|
||||||
|
enable: true,
|
||||||
|
countList: [],
|
||||||
|
},
|
||||||
|
desc: '',
|
||||||
|
isShow: false,
|
||||||
|
isUsed: false,
|
||||||
|
frequency: 1,
|
||||||
|
} as IPrizeConfig,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
persist: {
|
||||||
|
enabled: true,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
// 如果要存储在localStorage中
|
||||||
|
storage: localStorage,
|
||||||
|
key: 'prizeConfig',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,37 +1,37 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia'
|
||||||
// import { IPrizeConfig } from '@/types/storeType';
|
// import { IPrizeConfig } from '@/types/storeType';
|
||||||
export const useSystem = defineStore('system', {
|
export const useSystem = defineStore('system', {
|
||||||
state() {
|
state() {
|
||||||
return {
|
return {
|
||||||
isMobile:false,
|
isMobile: false,
|
||||||
isChrome:true
|
isChrome: true,
|
||||||
};
|
}
|
||||||
|
},
|
||||||
|
getters: {
|
||||||
|
getIsMobile(state) {
|
||||||
|
return state.isMobile
|
||||||
},
|
},
|
||||||
getters: {
|
getIsChrome(state) {
|
||||||
getIsMobile(state) {
|
return state.isChrome
|
||||||
return state.isMobile;
|
|
||||||
},
|
|
||||||
getIsChrome(state) {
|
|
||||||
return state.isChrome;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
},
|
||||||
setIsMobile(isMobile: boolean) {
|
actions: {
|
||||||
this.isMobile = isMobile;
|
setIsMobile(isMobile: boolean) {
|
||||||
},
|
this.isMobile = isMobile
|
||||||
setIsChrome(isChrome: boolean) {
|
|
||||||
this.isChrome = isChrome;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
persist: {
|
setIsChrome(isChrome: boolean) {
|
||||||
enabled: true,
|
this.isChrome = isChrome
|
||||||
strategies: [
|
|
||||||
{
|
|
||||||
// 如果要存储在localStorage中
|
|
||||||
// storage: localStorage,
|
|
||||||
// key: 'globalConfig',
|
|
||||||
// paths: ['globalConfig'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
persist: {
|
||||||
|
enabled: true,
|
||||||
|
strategies: [
|
||||||
|
{
|
||||||
|
// 如果要存储在localStorage中
|
||||||
|
// storage: localStorage,
|
||||||
|
// key: 'globalConfig',
|
||||||
|
// paths: ['globalConfig'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,52 +1,52 @@
|
|||||||
export interface IPersonConfig {
|
export interface IPersonConfig {
|
||||||
id: number;
|
id: number
|
||||||
uid: string;
|
uid: string
|
||||||
name: string;
|
name: string
|
||||||
department: string;
|
department: string
|
||||||
identity: string;
|
identity: string
|
||||||
isWin: boolean;
|
isWin: boolean
|
||||||
x: number;
|
x: number
|
||||||
y: number
|
y: number
|
||||||
createTime: string;
|
createTime: string
|
||||||
updateTime: string;
|
updateTime: string
|
||||||
prizeName: string[];
|
prizeName: string[]
|
||||||
prizeId: string[];
|
prizeId: string[]
|
||||||
prizeTime: string[];
|
prizeTime: string[]
|
||||||
}
|
}
|
||||||
export type Separate = {
|
export interface Separate {
|
||||||
id: string,
|
id: string
|
||||||
count: number,
|
count: number
|
||||||
isUsedCount: number,
|
isUsedCount: number
|
||||||
}
|
}
|
||||||
export interface IPrizeConfig {
|
export interface IPrizeConfig {
|
||||||
id: number | string;
|
id: number | string
|
||||||
name: string;
|
name: string
|
||||||
sort: number;
|
sort: number
|
||||||
isAll: boolean;
|
isAll: boolean
|
||||||
count: number;
|
count: number
|
||||||
isUsedCount: number,
|
isUsedCount: number
|
||||||
picture: {
|
picture: {
|
||||||
id: string | number,
|
id: string | number
|
||||||
name: string,
|
name: string
|
||||||
url: string
|
url: string
|
||||||
};
|
}
|
||||||
separateCount: {
|
separateCount: {
|
||||||
enable: boolean,
|
enable: boolean
|
||||||
countList: Separate[],
|
countList: Separate[]
|
||||||
};
|
}
|
||||||
desc: string;
|
desc: string
|
||||||
isShow: boolean;
|
isShow: boolean
|
||||||
isUsed: boolean,
|
isUsed: boolean
|
||||||
frequency: number;
|
frequency: number
|
||||||
}
|
}
|
||||||
export interface IMusic {
|
export interface IMusic {
|
||||||
id: string,
|
id: string
|
||||||
name: string,
|
name: string
|
||||||
url: string,
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IImage {
|
export interface IImage {
|
||||||
id: string,
|
id: string
|
||||||
name: string,
|
name: string
|
||||||
url: string,
|
url: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
export function getToken() {
|
export function getToken() {
|
||||||
return window.localStorage.getItem('userToken');
|
return window.localStorage.getItem('userToken')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,43 +1,43 @@
|
|||||||
// 判断颜色是否rgb或者rgba
|
// 判断颜色是否rgb或者rgba
|
||||||
export function isRgbOrRgba(color: string) {
|
export function isRgbOrRgba(color: string) {
|
||||||
return color.indexOf('rgb') > -1 || color.indexOf('rgba') > -1;
|
return color.includes('rgb') || color.includes('rgba')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断是否hex形式
|
// 判断是否hex形式
|
||||||
export function isHex(color: string) {
|
export function isHex(color: string) {
|
||||||
return color.indexOf('#') > -1;
|
return color.includes('#')
|
||||||
}
|
}
|
||||||
|
|
||||||
// 把hex颜色转成rgb数值类型
|
// 把hex颜色转成rgb数值类型
|
||||||
export function hexToRgba(hex: string) {
|
export function hexToRgba(hex: string) {
|
||||||
const r = parseInt(hex.slice(1, 3), 16);
|
const r = Number.parseInt(hex.slice(1, 3), 16)
|
||||||
const g = parseInt(hex.slice(3, 5), 16);
|
const g = Number.parseInt(hex.slice(3, 5), 16)
|
||||||
const b = parseInt(hex.slice(5, 7), 16);
|
const b = Number.parseInt(hex.slice(5, 7), 16)
|
||||||
|
|
||||||
return {r,g,b}
|
return { r, g, b }
|
||||||
}
|
}
|
||||||
// 把rgb数组转化成r g b 数值
|
// 把rgb数组转化成r g b 数值
|
||||||
export function rgbToRgba(rgb: string) {
|
export function rgbToRgba(rgb: string) {
|
||||||
const rgbArr = rgb.split('(')[1].split(')')[0].split(',');
|
const rgbArr = rgb.split('(')[1].split(')')[0].split(',')
|
||||||
|
|
||||||
return {r:rgbArr[0],g:rgbArr[1],b:rgbArr[2]}
|
return { r: rgbArr[0], g: rgbArr[1], b: rgbArr[2] }
|
||||||
}
|
}
|
||||||
|
|
||||||
// 组成rgb颜色添加透明度
|
// 组成rgb颜色添加透明度
|
||||||
export function rgba(color: string, opacity: number) {
|
export function rgba(color: string, opacity: number) {
|
||||||
opacity = opacity || 1;
|
opacity = opacity || 1
|
||||||
let rgbaStr=''
|
let rgbaStr = ''
|
||||||
// 判断是否是hex颜色
|
// 判断是否是hex颜色
|
||||||
if (isHex(color)) {
|
if (isHex(color)) {
|
||||||
const {r,g,b} = hexToRgba(color);
|
const { r, g, b } = hexToRgba(color)
|
||||||
rgbaStr = `rgba(${r},${g},${b},${opacity})`
|
rgbaStr = `rgba(${r},${g},${b},${opacity})`
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
const {r,g,b} = rgbToRgba(color)
|
const { r, g, b } = rgbToRgba(color)
|
||||||
rgbaStr = `rgba(${r},${g},${b},${opacity})`
|
rgbaStr = `rgba(${r},${g},${b},${opacity})`
|
||||||
}
|
}
|
||||||
|
|
||||||
return rgbaStr
|
return rgbaStr
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rgbToHex(color:string) {
|
export function rgbToHex(color:string) {
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
export const readFileBinary = (file: any): Promise<any> => {
|
export function readFileBinary(file: any): Promise<any> {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsBinaryString(file)
|
reader.readAsBinaryString(file)
|
||||||
reader.onload = (ev: any) => {
|
reader.onload = (ev: any) => {
|
||||||
resolve(ev.target.result)
|
resolve(ev.target.result)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const readFileData = (file: any): Promise<{dataUrl:string,fileName:string}> => {
|
export function readFileData(file: any): Promise<{ dataUrl: string, fileName: string }> {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const reader = new FileReader()
|
const reader = new FileReader()
|
||||||
reader.readAsDataURL(file)
|
reader.readAsDataURL(file)
|
||||||
reader.onload = (ev: any) => {
|
reader.onload = (ev: any) => {
|
||||||
resolve({dataUrl:ev.target.result,fileName:file.name})
|
resolve({ dataUrl: ev.target.result, fileName: file.name })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs'
|
||||||
// 筛选人员数据
|
// 筛选人员数据
|
||||||
export const filterData = (tableData: any[], localRowCount: number, startIndex = 0) => {
|
export function filterData(tableData: any[], localRowCount: number) {
|
||||||
const dataLength = tableData.length
|
const dataLength = tableData.length
|
||||||
let j = 0;
|
let j = 0
|
||||||
for (let i = 0; i < dataLength; i++) {
|
for (let i = 0; i < dataLength; i++) {
|
||||||
if (i % localRowCount === 0) {
|
if (i % localRowCount === 0) {
|
||||||
j++;
|
j++
|
||||||
}
|
|
||||||
tableData[i].x = i % localRowCount + 1;
|
|
||||||
tableData[i].y = j;
|
|
||||||
tableData[i].id = i;
|
|
||||||
// 是否中奖
|
|
||||||
}
|
}
|
||||||
|
tableData[i].x = i % localRowCount + 1
|
||||||
|
tableData[i].y = j
|
||||||
|
tableData[i].id = i
|
||||||
|
// 是否中奖
|
||||||
|
}
|
||||||
|
|
||||||
return tableData
|
return tableData
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addOtherInfo = (personList: any[]) => {
|
export function addOtherInfo(personList: any[]) {
|
||||||
const len = personList.length;
|
const len = personList.length
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
personList[i].id = i
|
personList[i].id = i
|
||||||
personList[i].createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss');
|
personList[i].createTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
|
||||||
personList[i].updateTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss');
|
personList[i].updateTime = dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss')
|
||||||
personList[i].prizeName = [] as string[];
|
personList[i].prizeName = [] as string[]
|
||||||
personList[i].prizeTime = [] as string[];
|
personList[i].prizeTime = [] as string[]
|
||||||
personList[i].prizeId = [];
|
personList[i].prizeId = []
|
||||||
personList[i].isWin = false
|
personList[i].isWin = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return personList
|
return personList
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectCard = (cardIndexArr: number[], tableLength: number, personId: number): number => {
|
export function selectCard(cardIndexArr: number[], tableLength: number, personId: number): number {
|
||||||
const cardIndex = Math.round(Math.random() * (tableLength - 1));
|
const cardIndex = Math.round(Math.random() * (tableLength - 1))
|
||||||
if (cardIndexArr.includes(cardIndex)) {
|
if (cardIndexArr.includes(cardIndex)) {
|
||||||
return selectCard(cardIndexArr, tableLength, personId)
|
return selectCard(cardIndexArr, tableLength, personId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cardIndex
|
return cardIndex
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
// 提取有哪些字段
|
// 提取有哪些字段
|
||||||
export const extractFields = (data: any) => {
|
export function extractFields(data: any) {
|
||||||
const item=data[0];
|
const item = data[0]
|
||||||
// 排除id x y,其他都加入数组
|
// 排除id x y,其他都加入数组
|
||||||
const keys = Object.keys(item).filter(key => key!== 'id' && key!== 'x' && key!== 'y');
|
const keys = Object.keys(item).filter(key => key !== 'id' && key !== 'x' && key !== 'y')
|
||||||
if(keys.length>0){
|
if (keys.length > 0) {
|
||||||
// 返回数组key value
|
// 返回数组key value
|
||||||
return keys.map(key => ({label:key,value:true}));
|
return keys.map(key => ({ label: key, value: true }))
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,39 +1,31 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, watch, onMounted } from 'vue'
|
import i18n, { languageList } from '@/locales/i18n'
|
||||||
import useStore from '@/store'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import { themeChange } from 'theme-change';
|
|
||||||
import zod from 'zod';
|
|
||||||
import daisyuiThemes from 'daisyui/src/theming/themes'
|
|
||||||
import { ColorPicker } from 'vue3-colorpicker';
|
|
||||||
import 'vue3-colorpicker/style.css';
|
|
||||||
import { isRgbOrRgba, isHex } from '@/utils/color'
|
|
||||||
import PatternSetting from './components/PatternSetting.vue'
|
|
||||||
|
|
||||||
|
import useStore from '@/store'
|
||||||
|
import { isHex, isRgbOrRgba } from '@/utils/color'
|
||||||
|
import daisyuiThemes from 'daisyui/src/theming/themes'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { themeChange } from 'theme-change'
|
||||||
|
import { onMounted, ref, watch } from 'vue'
|
||||||
|
import { ColorPicker } from 'vue3-colorpicker'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import zod from 'zod'
|
||||||
|
import PatternSetting from './components/PatternSetting.vue'
|
||||||
|
import 'vue3-colorpicker/style.css'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
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,
|
const { 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, getImageList: imageList,
|
||||||
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)
|
} = 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
|
||||||
}
|
}
|
||||||
const isRowCountChange = ref(0) //0未改变,1改变,2加载中
|
const isRowCountChange = ref(0) // 0未改变,1改变,2加载中
|
||||||
const themeValue = ref(localTheme.value.name)
|
const themeValue = ref(localTheme.value.name)
|
||||||
const topTitleValue = ref(structuredClone(topTitle.value))
|
const topTitleValue = ref(structuredClone(topTitle.value))
|
||||||
const cardColorValue = ref(structuredClone(cardColor.value))
|
const cardColorValue = ref(structuredClone(cardColor.value))
|
||||||
@@ -42,68 +34,68 @@ const textColorValue = ref(structuredClone(textColor.value))
|
|||||||
const cardSizeValue = ref(structuredClone(cardSize.value))
|
const cardSizeValue = ref(structuredClone(cardSize.value))
|
||||||
const textSizeValue = ref(structuredClone(textSize.value))
|
const textSizeValue = ref(structuredClone(textSize.value))
|
||||||
const rowCountValue = ref(structuredClone(rowCount.value))
|
const rowCountValue = ref(structuredClone(rowCount.value))
|
||||||
|
const languageValue = ref(structuredClone(userLanguage.value))
|
||||||
const isShowPrizeListValue = ref(structuredClone(isShowPrizeList.value))
|
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 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: i18n.global.t('error.require'),
|
||||||
invalid_type_error: '必须填入数字',
|
invalid_type_error: i18n.global.t('error.requireNumber'),
|
||||||
})
|
})
|
||||||
.min(1, '最小为1')
|
.min(1, i18n.global.t('error.minNumber1'))
|
||||||
.max(100, '最大为100')
|
.max(100, i18n.global.t('error.maxNumber100')),
|
||||||
// 格式化
|
// 格式化
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
type ValidatePayload = zod.infer<typeof schema>
|
type ValidatePayload = zod.infer<typeof schema>
|
||||||
const payload: ValidatePayload = {
|
const payload: ValidatePayload = {
|
||||||
rowCount: formData.value.rowCount,
|
rowCount: formData.value.rowCount,
|
||||||
}
|
}
|
||||||
const parseSchema = (props: ValidatePayload) => {
|
function parseSchema(props: ValidatePayload) {
|
||||||
return schema.parseAsync(props)
|
return schema.parseAsync(props)
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetPersonLayout = () => {
|
function resetPersonLayout() {
|
||||||
isRowCountChange.value = 2
|
isRowCountChange.value = 2
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const alreadyLen = alreadyPersonList.value.length
|
const alreadyLen = alreadyPersonList.value.length
|
||||||
const notLen = notPersonList.value.length
|
const notLen = notPersonList.value.length
|
||||||
if (alreadyLen <= 0 && notLen <= 0) {
|
if (alreadyLen <= 0 && notLen <= 0) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const allPersonList = alreadyPersonList.value.concat(notPersonList.value)
|
const allPersonList = alreadyPersonList.value.concat(notPersonList.value)
|
||||||
const newAlreadyPersonList = allPersonList.slice(0, alreadyLen)
|
const newAlreadyPersonList = allPersonList.slice(0, alreadyLen)
|
||||||
const newNotPersonList = allPersonList.slice(alreadyLen, notLen + alreadyLen)
|
const newNotPersonList = allPersonList.slice(alreadyLen, notLen + alreadyLen)
|
||||||
personConfig.deleteAllPerson()
|
personConfig.deleteAllPerson()
|
||||||
personConfig.addNotPersonList(newNotPersonList)
|
personConfig.addNotPersonList(newNotPersonList)
|
||||||
personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
|
personConfig.addAlreadyPersonList(newAlreadyPersonList, null)
|
||||||
|
|
||||||
isRowCountChange.value = 0
|
isRowCountChange.value = 0
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearPattern = () => {
|
function clearPattern() {
|
||||||
globalConfig.setPatternList([] as number[])
|
globalConfig.setPatternList([] as number[])
|
||||||
}
|
}
|
||||||
const resetPattern = () => {
|
function resetPattern() {
|
||||||
globalConfig.resetPatternList()
|
globalConfig.resetPatternList()
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetData = () => {
|
function resetData() {
|
||||||
globalConfig.reset();
|
globalConfig.reset()
|
||||||
personConfig.reset();
|
personConfig.reset()
|
||||||
prizeConfig.resetDefault();
|
prizeConfig.resetDefault()
|
||||||
// 刷新页面
|
// 刷新页面
|
||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
// const handleChangeShowFields = (fieldItem: any) => {
|
// const handleChangeShowFields = (fieldItem: any) => {
|
||||||
@@ -115,210 +107,244 @@ const resetData = () => {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
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) => {
|
||||||
if (res.rowCount) {
|
if (res.rowCount) {
|
||||||
isRowCountChange.value = 1
|
isRowCountChange.value = 1
|
||||||
globalConfig.setRowCount(res.rowCount)
|
globalConfig.setRowCount(res.rowCount)
|
||||||
}
|
}
|
||||||
})
|
}).catch((err) => {
|
||||||
.catch(err => {
|
formErr.value.rowCount = err.issues[0].message
|
||||||
formErr.value.rowCount = err.issues[0].message
|
})
|
||||||
})
|
|
||||||
})
|
})
|
||||||
watch(topTitleValue, (val) => {
|
|
||||||
globalConfig.setTopTitle(val)
|
|
||||||
}),
|
|
||||||
|
|
||||||
watch(themeValue, (val: any) => {
|
watch(topTitleValue, (val) => {
|
||||||
const selectedThemeDetail = daisyuiThemeList.value[val]
|
globalConfig.setTopTitle(val)
|
||||||
globalConfig.setTheme({ name: val, detail: selectedThemeDetail })
|
})
|
||||||
themeChange(val)
|
watch(themeValue, (val: any) => {
|
||||||
if (selectedThemeDetail.primary && (isHex(selectedThemeDetail.primary) || isRgbOrRgba(selectedThemeDetail.primary))) {
|
const selectedThemeDetail = daisyuiThemeList.value[val]
|
||||||
globalConfig.setCardColor(selectedThemeDetail.primary)
|
globalConfig.setTheme({ name: val, detail: selectedThemeDetail })
|
||||||
}
|
themeChange(val)
|
||||||
}, { deep: true })
|
if (selectedThemeDetail.primary && (isHex(selectedThemeDetail.primary) || isRgbOrRgba(selectedThemeDetail.primary))) {
|
||||||
|
globalConfig.setCardColor(selectedThemeDetail.primary)
|
||||||
|
}
|
||||||
|
}, { deep: true })
|
||||||
|
|
||||||
watch(cardColorValue, (val: string) => {
|
watch(cardColorValue, (val: string) => {
|
||||||
globalConfig.setCardColor(val)
|
globalConfig.setCardColor(val)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
watch(luckyCardColorValue, (val: string) => {
|
watch(luckyCardColorValue, (val: string) => {
|
||||||
globalConfig.setLuckyCardColor(val)
|
globalConfig.setLuckyCardColor(val)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
watch(patternColorValue, (val: string) => {
|
watch(patternColorValue, (val: string) => {
|
||||||
globalConfig.setPatterColor(val)
|
globalConfig.setPatterColor(val)
|
||||||
})
|
})
|
||||||
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; }) => {
|
|
||||||
globalConfig.setCardSize(val)
|
watch(cardSizeValue, (val: { width: number, height: number }) => {
|
||||||
}, { deep: true }),
|
globalConfig.setCardSize(val)
|
||||||
watch(isShowPrizeListValue, () => {
|
}, { deep: true })
|
||||||
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
|
||||||
})
|
watch(isShowPrizeListValue, () => {
|
||||||
watch(backgroundImageValue, (val: {}) => {
|
globalConfig.setIsShowPrizeList(isShowPrizeListValue.value)
|
||||||
globalConfig.setBackground(val)
|
})
|
||||||
|
watch(backgroundImageValue, (val) => {
|
||||||
|
globalConfig.setBackground(val)
|
||||||
|
})
|
||||||
|
watch(languageValue, (val: string) => {
|
||||||
|
globalConfig.setLanguage(val)
|
||||||
})
|
})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<dialog id="my_modal_1" ref="resetDataDialogRef" class="border-none modal">
|
<dialog id="my_modal_1" ref="resetDataDialogRef" class="border-none modal">
|
||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<h3 class="text-lg font-bold">提示!</h3>
|
<h3 class="text-lg font-bold">
|
||||||
<p class="py-4">该操作会重置所有数据,是否继续?</p>
|
{{ t('dialog.titleTip') }}
|
||||||
<div class="modal-action">
|
</h3>
|
||||||
<form method="dialog" class="flex gap-3">
|
<p class="py-4">
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
{{ t('dialog.dialogResetAllData') }}
|
||||||
<button class="btn" @click="resetDataDialogRef.close()">取消</button>
|
</p>
|
||||||
<button class="btn" @click="resetData">确定</button>
|
<div class="modal-action">
|
||||||
</form>
|
<form method="dialog" class="flex gap-3">
|
||||||
</div>
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
</div>
|
<button class="btn" @click="resetDataDialogRef.close()">
|
||||||
</dialog>
|
{{ t(`button.cancel`) }}
|
||||||
<div>
|
</button>
|
||||||
<h2>全局配置</h2>
|
<button class="btn" @click="resetData">
|
||||||
<div class="mb-8">
|
{{ t('button.confirm') }}
|
||||||
<button class="btn btn-sm btn-primary" @click="resetDataDialogRef.showModal()">重置所有数据</button>
|
</button>
|
||||||
</div>
|
</form>
|
||||||
<label class="flex flex-row items-center w-full gap-24 mb-10 form-control">
|
</div>
|
||||||
<div class="">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">标题</span>
|
|
||||||
</div>
|
|
||||||
<input type="text" v-model="topTitleValue" placeholder="输入标题"
|
|
||||||
class="w-full max-w-xs input input-bordered" />
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<label class="flex flex-row items-center w-full gap-24 mb-10 form-control">
|
|
||||||
<div class="">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">列数</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="formData.rowCount" placeholder="Type here"
|
|
||||||
class="w-full max-w-xs input input-bordered" />
|
|
||||||
<div class="help">
|
|
||||||
<span class="text-sm text-red-400 help-text" v-if="formErr.rowCount">
|
|
||||||
{{ formErr.rowCount }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="tooltip" data-tip="该项比较耗费时间和性能">
|
|
||||||
<button class="mt-5 btn btn-info btn-sm" :disabled="isRowCountChange != 1"
|
|
||||||
@click="resetPersonLayout">
|
|
||||||
<span>重设布局</span>
|
|
||||||
<span class="loading loading-ring loading-md" v-show="isRowCountChange == 2"></span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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="themeValue">
|
|
||||||
<option disabled selected>选取主题</option>
|
|
||||||
<option v-for="(item, index) in themeList" :key="index" :value="item">{{ item }}</option>
|
|
||||||
</select>
|
|
||||||
</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">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">卡片颜色</span>
|
|
||||||
</div>
|
|
||||||
<ColorPicker ref="colorPickerRef" v-model="cardColorValue" v-model:pure-color="cardColorValue">
|
|
||||||
</ColorPicker>
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">中奖卡片颜色</span>
|
|
||||||
</div>
|
|
||||||
<ColorPicker ref="colorPickerRef" v-model="luckyCardColorValue" v-model:pure-color="luckyCardColorValue">
|
|
||||||
</ColorPicker>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<label class="w-full max-w-xs form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">文字颜色</span>
|
|
||||||
</div>
|
|
||||||
<ColorPicker ref="colorPickerRef" v-model="textColorValue" v-model:pure-color="textColorValue">
|
|
||||||
</ColorPicker>
|
|
||||||
</label>
|
|
||||||
<label class="flex flex-row w-full max-w-xs gap-10 mb-10 form-control">
|
|
||||||
<div>
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">卡片宽度</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="cardSizeValue.width" placeholder="Type here"
|
|
||||||
class="w-full max-w-xs input input-bordered" />
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">卡片高度</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="cardSizeValue.height" placeholder="Type here"
|
|
||||||
class="w-full max-w-xs input input-bordered" />
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">文字大小</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="textSizeValue" placeholder="Type here"
|
|
||||||
class="w-full max-w-xs input input-bordered" />
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">高亮颜色</span>
|
|
||||||
</div>
|
|
||||||
<ColorPicker ref="colorPickerRef" v-model="patternColorValue" v-model:pure-color="patternColorValue">
|
|
||||||
</ColorPicker>
|
|
||||||
</label>
|
|
||||||
<label class="flex flex-row items-center w-full gap-24 mb-0 form-control">
|
|
||||||
<div>
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">图案设置</span>
|
|
||||||
</div>
|
|
||||||
<div class="h-auto">
|
|
||||||
<PatternSetting :rowCount="rowCount" :cardColor="cardColor" :patternColor="patternColor"
|
|
||||||
:patternList="patternList"></PatternSetting>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<div class="flex w-full h-24 gap-3 m-0">
|
|
||||||
<button class="mt-5 btn btn-info btn-sm" @click.stop="clearPattern">
|
|
||||||
<span>清空图案设置</span>
|
|
||||||
</button>
|
|
||||||
<div class="tooltip" data-tip="默认图案设置针对17列时有效,其他列数请自行设置">
|
|
||||||
<button class="mt-5 btn btn-info btn-sm" @click="resetPattern">
|
|
||||||
<span>默认图案设置</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label class="w-full max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">是否常显奖品列表</span>
|
|
||||||
</div>
|
|
||||||
<input type="checkbox" :checked="isShowPrizeListValue"
|
|
||||||
@change="isShowPrizeListValue = !isShowPrizeListValue"
|
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
|
||||||
</label>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<div>
|
||||||
|
<h2>{{ t('viewTitle.globalSetting') }}</h2>
|
||||||
|
<div class="mb-8">
|
||||||
|
<button class="btn btn-sm btn-primary" @click="resetDataDialogRef.showModal()">
|
||||||
|
{{ t('button.resetAllData') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<label class="flex flex-row items-center w-full gap-24 mb-10 form-control">
|
||||||
|
<div class="">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.title') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="topTitleValue" type="text" :placeholder="t('placeHolder.enterTitle')"
|
||||||
|
class="w-full max-w-xs input input-bordered"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="flex flex-row items-center w-full gap-24 mb-10 form-control">
|
||||||
|
<div class="">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.columnNumber') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="formData.rowCount" type="number" placeholder="Type here"
|
||||||
|
class="w-full max-w-xs input input-bordered"
|
||||||
|
>
|
||||||
|
<div class="help">
|
||||||
|
<span v-if="formErr.rowCount" class="text-sm text-red-400 help-text">
|
||||||
|
{{ formErr.rowCount }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="tooltip" :data-tip="t('tooltip.resetLayout')">
|
||||||
|
<button class="mt-5 btn btn-info btn-sm" :disabled="isRowCountChange !== 1" @click="resetPersonLayout">
|
||||||
|
<span>{{ t('button.setLayout') }}</span>
|
||||||
|
<span v-show="isRowCountChange === 2" class="loading loading-ring loading-md" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.language') }}</span>
|
||||||
|
</div>
|
||||||
|
<select v-model="languageValue" data-choose-theme class="w-full max-w-xs border-solid select border-1">
|
||||||
|
<option disabled selected>{{ t('table.language') }}</option>
|
||||||
|
<option v-for="item in languageList" :key="item.key" :value="item.key">{{ item.name }}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.theme') }}</span>
|
||||||
|
</div>
|
||||||
|
<select v-model="themeValue" data-choose-theme class="w-full max-w-xs border-solid select border-1">
|
||||||
|
<option disabled selected>{{ t('table.theme') }}</option>
|
||||||
|
<option v-for="(item, index) in themeList" :key="index" :value="item">{{ item }}</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.backgroundImage') }}</span>
|
||||||
|
</div>
|
||||||
|
<select
|
||||||
|
v-model="backgroundImageValue" data-choose-theme
|
||||||
|
class="w-full max-w-xs border-solid select border-1"
|
||||||
|
>
|
||||||
|
<option disabled selected>{{ t('table.backgroundImage') }}</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">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.cardColor') }}</span>
|
||||||
|
</div>
|
||||||
|
<ColorPicker ref="colorPickerRef" v-model="cardColorValue" v-model:pure-color="cardColorValue" />
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.winnerColor') }}</span>
|
||||||
|
</div>
|
||||||
|
<ColorPicker ref="colorPickerRef" v-model="luckyCardColorValue" v-model:pure-color="luckyCardColorValue" />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.textColor') }}</span>
|
||||||
|
</div>
|
||||||
|
<ColorPicker ref="colorPickerRef" v-model="textColorValue" v-model:pure-color="textColorValue" />
|
||||||
|
</label>
|
||||||
|
<label class="flex flex-row w-full max-w-xs gap-10 mb-10 form-control">
|
||||||
|
<div>
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.cardWidth') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="cardSizeValue.width" type="number" placeholder="Type here"
|
||||||
|
class="w-full max-w-xs input input-bordered"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.cardHeight') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="cardSizeValue.height" type="number" placeholder="Type here"
|
||||||
|
class="w-full max-w-xs input input-bordered"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.textSize') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="textSizeValue" type="number" placeholder="Type here"
|
||||||
|
class="w-full max-w-xs input input-bordered"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.highlightColor') }}</span>
|
||||||
|
</div>
|
||||||
|
<ColorPicker ref="colorPickerRef" v-model="patternColorValue" v-model:pure-color="patternColorValue" />
|
||||||
|
</label>
|
||||||
|
<label class="flex flex-row items-center w-full gap-24 mb-0 form-control">
|
||||||
|
<div>
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.patternSetting') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="h-auto">
|
||||||
|
<PatternSetting
|
||||||
|
:row-count="rowCount" :card-color="cardColor" :pattern-color="patternColor"
|
||||||
|
:pattern-list="patternList"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<div class="flex w-full h-24 gap-3 m-0">
|
||||||
|
<button class="mt-5 btn btn-info btn-sm" @click.stop="clearPattern">
|
||||||
|
<span>{{ t('button.clearPattern') }}</span>
|
||||||
|
</button>
|
||||||
|
<div class="tooltip" :data-tip="t('tooltip.defaultLayout')">
|
||||||
|
<button class="mt-5 btn btn-info btn-sm" @click="resetPattern">
|
||||||
|
<span>{{ t('button.DefaultPattern') }}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label class="w-full max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.alwaysDisplay') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="checkbox" :checked="isShowPrizeListValue" class="mt-2 border-solid checkbox checkbox-secondary border-1"
|
||||||
|
@change="isShowPrizeListValue = !isShowPrizeListValue"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,111 +1,118 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import type { IImage } from '@/types/storeType'
|
||||||
import { IImage } from '@/types/storeType'
|
import ImageSync from '@/components/ImageSync/index.vue'
|
||||||
|
import useStore from '@/store'
|
||||||
import { readFileData } from '@/utils/file'
|
import { readFileData } from '@/utils/file'
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import useStore from '@/store'
|
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import ImageSync from '@/components/ImageSync/index.vue'
|
import { onMounted, ref, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const globalConfig= useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const { getImageList:localImageList} = storeToRefs(globalConfig)
|
const { getImageList: localImageList } = storeToRefs(globalConfig)
|
||||||
const limitType = ref('image/*')
|
const limitType = ref('image/*')
|
||||||
const imgUploadToast = ref(0) //0是不显示,1是成功,2是失败,3是不是图片
|
const imgUploadToast = ref(0) // 0是不显示,1是成功,2是失败,3是不是图片
|
||||||
const imageDbStore = localforage.createInstance({
|
const imageDbStore = localforage.createInstance({
|
||||||
name: 'imgStore'
|
name: 'imgStore',
|
||||||
})
|
})
|
||||||
const handleFileChange = async (e: Event) => {
|
async function handleFileChange(e: Event) {
|
||||||
const isImage= /image*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
|
const isImage = /image*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
|
||||||
if (!isImage) {
|
if (!isImage) {
|
||||||
imgUploadToast.value = 3
|
imgUploadToast.value = 3
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let { dataUrl, fileName } = await readFileData(((e.target as HTMLInputElement).files as FileList)[0])
|
const { dataUrl, fileName } = await readFileData(((e.target as HTMLInputElement).files as FileList)[0])
|
||||||
imageDbStore.setItem(new Date().getTime().toString() + '+' + fileName, dataUrl)
|
imageDbStore.setItem(`${new Date().getTime().toString()}+${fileName}`, dataUrl)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
imgUploadToast.value = 1
|
imgUploadToast.value = 1
|
||||||
getImageDbStore()
|
getImageDbStore()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
imgUploadToast.value = 2
|
imgUploadToast.value = 2
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImageDbStore =async () => {
|
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, key) => {
|
||||||
globalConfig.addImage({
|
globalConfig.addImage({
|
||||||
id:key,
|
id: key,
|
||||||
name:key,
|
name: key,
|
||||||
url:'Storage'
|
url: 'Storage',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeImage=(item:IImage)=>{
|
function removeImage(item: IImage) {
|
||||||
if(item.url=='Storage'){
|
if (item.url === 'Storage') {
|
||||||
imageDbStore.removeItem(item.id).then(() => {
|
imageDbStore.removeItem(item.id).then(() => {
|
||||||
globalConfig.removeImage(item.id)
|
globalConfig.removeImage(item.id)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
globalConfig.removeImage(item.id)
|
globalConfig.removeImage(item.id)
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// getImageDbStore()
|
// getImageDbStore()
|
||||||
})
|
})
|
||||||
watch(() => imgUploadToast.value, (val) => {
|
watch(() => imgUploadToast.value, (val) => {
|
||||||
if (val !== 0) {
|
if (val !== 0) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
imgUploadToast.value = 0
|
imgUploadToast.value = 0
|
||||||
}, 2000)
|
}, 2000)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="toast toast-top toast-end">
|
<div class="toast toast-top toast-end">
|
||||||
<div class="alert alert-error" v-if="imgUploadToast == 2">
|
<div v-if="imgUploadToast === 2" class="alert alert-error">
|
||||||
<span>上传失败</span>
|
<span>{{ t('error.uploadFail') }}</span>
|
||||||
</div>
|
|
||||||
<div class="alert alert-success" v-if="imgUploadToast == 1">
|
|
||||||
<span>上传成功</span>
|
|
||||||
</div>
|
|
||||||
<div class="alert alert-error" v-if="imgUploadToast == 3">
|
|
||||||
<span>不是图片</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="imgUploadToast === 1" class="alert alert-success">
|
||||||
|
<span>{{ t('error.uploadSuccess') }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-if="imgUploadToast === 3" class="alert alert-error">
|
||||||
|
<span>{{ t('error.notImage') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="explore">
|
<label for="explore">
|
||||||
<input type="file" class="" id="explore" style="display: none" @change="handleFileChange"
|
<input
|
||||||
:accept="limitType" />
|
id="explore" type="file" class="" style="display: none" :accept="limitType"
|
||||||
<span class="btn btn-primary btn-sm">上传图片</span>
|
@change="handleFileChange"
|
||||||
</label>
|
>
|
||||||
</div>
|
<span class="btn btn-primary btn-sm">{{ t('button.upload') }}</span>
|
||||||
<ul class="p-0">
|
</label>
|
||||||
<li v-for="item in localImageList" :key="item.id" class="mb-3">
|
|
||||||
<div class="flex items-center gap-8">
|
|
||||||
<div class="avatar h-14">
|
|
||||||
<div class="w-12 h-12 mask mask-squircle hover:w-14 hover:h-14">
|
|
||||||
<!-- <img v-if="item.url!=='Storage'" :src="item.url" alt="Avatar Tailwind CSS Component" /> -->
|
|
||||||
<ImageSync :imgItem="item"></ImageSync>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="w-64">
|
|
||||||
<div class="overflow-hidden font-bold whitespace-nowrap text-ellipsis">{{ item.name}}</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<button class="btn btn-error btn-xs" @click="removeImage(item)">删除</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
|
<ul class="p-0">
|
||||||
|
<li v-for="item in localImageList" :key="item.id" class="mb-3">
|
||||||
|
<div class="flex items-center gap-8">
|
||||||
|
<div class="avatar h-14">
|
||||||
|
<div class="w-12 h-12 mask mask-squircle hover:w-14 hover:h-14">
|
||||||
|
<!-- <img v-if="item.url!=='Storage'" :src="item.url" alt="Avatar Tailwind CSS Component" /> -->
|
||||||
|
<ImageSync :img-item="item" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="w-64">
|
||||||
|
<div class="overflow-hidden font-bold whitespace-nowrap text-ellipsis">
|
||||||
|
{{ item.name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-error btn-xs" @click="removeImage(item)">
|
||||||
|
{{ t('button.upload') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,102 +1,113 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted } from 'vue'
|
import type { IMusic } from '@/types/storeType'
|
||||||
import {storeToRefs } from 'pinia'
|
import useStore from '@/store'
|
||||||
import { IMusic } from '@/types/storeType';
|
|
||||||
import { readFileData } from '@/utils/file'
|
import { readFileData } from '@/utils/file'
|
||||||
import useStore from '@/store';
|
|
||||||
|
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
const audioUploadToast = ref(0) //0是不显示,1是成功,2是失败,3是不是图片
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
|
const audioUploadToast = ref(0) // 0是不显示,1是成功,2是失败,3是不是图片
|
||||||
const audioDbStore = localforage.createInstance({
|
const audioDbStore = localforage.createInstance({
|
||||||
name: 'audioStore'
|
name: 'audioStore',
|
||||||
})
|
})
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
|
|
||||||
const { getMusicList: localMusicList } = storeToRefs(globalConfig);
|
const { getMusicList: localMusicList } = storeToRefs(globalConfig)
|
||||||
const limitType = ref('audio/*')
|
const limitType = ref('audio/*')
|
||||||
const localMusicListValue = ref(localMusicList)
|
const localMusicListValue = ref(localMusicList)
|
||||||
const play = async (item: IMusic) => {
|
async function play(item: IMusic) {
|
||||||
globalConfig.setCurrentMusic(item,false)
|
globalConfig.setCurrentMusic(item, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteMusic = (item: IMusic) => {
|
function deleteMusic(item: IMusic) {
|
||||||
globalConfig.removeMusic(item.id)
|
globalConfig.removeMusic(item.id)
|
||||||
audioDbStore.removeItem(item.name)
|
audioDbStore.removeItem(item.name)
|
||||||
// setTimeout(()=>{
|
// setTimeout(()=>{
|
||||||
// localMusicListValue.value=localMusicList
|
// localMusicListValue.value=localMusicList
|
||||||
// },100)
|
// },100)
|
||||||
}
|
}
|
||||||
const resetMusic = () => {
|
function resetMusic() {
|
||||||
globalConfig.resetMusicList()
|
globalConfig.resetMusicList()
|
||||||
audioDbStore.clear()
|
audioDbStore.clear()
|
||||||
}
|
}
|
||||||
const deleteAll = () => {
|
function deleteAll() {
|
||||||
globalConfig.clearMusicList()
|
globalConfig.clearMusicList()
|
||||||
audioDbStore.clear()
|
audioDbStore.clear()
|
||||||
}
|
}
|
||||||
const getMusicDbStore = async () => {
|
async function getMusicDbStore() {
|
||||||
const keys = await audioDbStore.keys()
|
const keys = await audioDbStore.keys()
|
||||||
if (keys.length > 0) {
|
if (keys.length > 0) {
|
||||||
audioDbStore.iterate((value: string, key: string) => {
|
audioDbStore.iterate((value: string, key: string) => {
|
||||||
globalConfig.addMusic({
|
globalConfig.addMusic({
|
||||||
id: key + new Date().getTime().toString(),
|
id: key + new Date().getTime().toString(),
|
||||||
name: key,
|
name: key,
|
||||||
url: 'Storage',
|
url: 'Storage',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleFileChange = async (e: Event) => {
|
async function handleFileChange(e: Event) {
|
||||||
const isAudio = /audio*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
|
const isAudio = /audio*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
|
||||||
if (!isAudio) {
|
if (!isAudio) {
|
||||||
audioUploadToast.value = 3
|
audioUploadToast.value = 3
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let { dataUrl, fileName } = await readFileData(((e.target as HTMLInputElement).files as FileList)[0])
|
const { dataUrl, fileName } = await readFileData(((e.target as HTMLInputElement).files as FileList)[0])
|
||||||
audioDbStore.setItem(new Date().getTime().toString() + '+' + fileName, dataUrl)
|
audioDbStore.setItem(`${new Date().getTime().toString()}+${fileName}`, dataUrl)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
audioUploadToast.value = 1
|
audioUploadToast.value = 1
|
||||||
getMusicDbStore()
|
getMusicDbStore()
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
audioUploadToast.value = 2
|
audioUploadToast.value = 2
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getMusicDbStore()
|
getMusicDbStore()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex gap-3">
|
<div class="flex gap-3">
|
||||||
<button class="btn btn-primary btn-sm" @click="resetMusic">重置音乐列表</button>
|
<button class="btn btn-primary btn-sm" @click="resetMusic">
|
||||||
<label for="explore">
|
{{ t('button.reset') }}
|
||||||
<input type="file" class="" id="explore" style="display: none" @change="handleFileChange"
|
</button>
|
||||||
:accept="limitType" />
|
<label for="explore">
|
||||||
<span class="btn btn-primary btn-sm">上传音乐</span>
|
<input
|
||||||
</label>
|
id="explore" type="file" class="" style="display: none" :accept="limitType"
|
||||||
<button class="btn btn-error btn-sm" @click="deleteAll">删除所有</button>
|
@change="handleFileChange"
|
||||||
</div>
|
>
|
||||||
<div>
|
<span class="btn btn-primary btn-sm">{{ t('button.upload') }}</span>
|
||||||
<ul class="p-0">
|
</label>
|
||||||
<li v-for="item in localMusicListValue" :key="item.id" class="flex items-center gap-6 pb-2 mb-3 divide-y">
|
<button class="btn btn-error btn-sm" @click="deleteAll">
|
||||||
<div class="mr-12 overflow-hidden w-72 whitespace-nowrap text-ellipsis">
|
{{ t('button.allDelete') }}
|
||||||
<span>
|
</button>
|
||||||
{{ item.name }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-3">
|
|
||||||
<button class="btn btn-primary btn-xs" @click="play(item)">播放</button>
|
|
||||||
<button class="btn btn-error btn-xs" @click="deleteMusic(item)">删除</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<ul class="p-0">
|
||||||
|
<li v-for="item in localMusicListValue" :key="item.id" class="flex items-center gap-6 pb-2 mb-3 divide-y">
|
||||||
|
<div class="mr-12 overflow-hidden w-72 whitespace-nowrap text-ellipsis">
|
||||||
|
<span>
|
||||||
|
{{ item.name }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="btn btn-primary btn-xs" @click="play(item)">
|
||||||
|
{{ t('button.play') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-error btn-xs" @click="deleteMusic(item)">
|
||||||
|
{{ t('button.delete') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,45 +1,46 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import {computed} from 'vue';
|
import { computed } from 'vue'
|
||||||
const props=defineProps({
|
|
||||||
rowCount:{
|
const props = defineProps({
|
||||||
type:Number,
|
rowCount: {
|
||||||
default:17
|
type: Number,
|
||||||
},
|
default: 17,
|
||||||
cardColor:{
|
},
|
||||||
type:String,
|
cardColor: {
|
||||||
default:'#fff'
|
type: String,
|
||||||
},
|
default: '#fff',
|
||||||
patternColor:{
|
},
|
||||||
type:String,
|
patternColor: {
|
||||||
default:'#000'
|
type: String,
|
||||||
},
|
default: '#000',
|
||||||
patternList:{
|
},
|
||||||
type:Array,
|
patternList: {
|
||||||
default:()=>[]
|
type: Array,
|
||||||
}
|
default: () => [],
|
||||||
|
},
|
||||||
})
|
})
|
||||||
const data=computed(()=>{
|
const data = computed(() => {
|
||||||
return props
|
return props
|
||||||
})
|
})
|
||||||
|
|
||||||
const updatePatternList=(event:Event,item:number)=>{
|
function updatePatternList(event: Event, item: number) {
|
||||||
if(data.value.patternList.includes(item)){
|
if (data.value.patternList.includes(item)) {
|
||||||
const index=data.value.patternList.indexOf(item)
|
const index = data.value.patternList.indexOf(item)
|
||||||
data.value.patternList.splice(index,1)
|
data.value.patternList.splice(index, 1)
|
||||||
}else{
|
}
|
||||||
data.value.patternList.push(item)
|
else {
|
||||||
}
|
data.value.patternList.push(item)
|
||||||
// emits
|
}
|
||||||
|
// emits
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full h-auto" >
|
<div class="w-full h-auto">
|
||||||
<ul class="pattern-list" :style="{gridTemplateColumns:'repeat('+data.rowCount+',1fr)'}">
|
<ul class="pattern-list" :style="{ gridTemplateColumns: `repeat(${data.rowCount},1fr)` }">
|
||||||
<li @click.stop="(event)=>updatePatternList(event,item)" class="w-5 h-5" v-for="item in data.rowCount*7" :key="item" :style="{backgroundColor:data.patternList.includes(item)?data.patternColor:data.cardColor}">
|
<li v-for="item in data.rowCount * 7" :key="item" class="w-5 h-5" :style="{ backgroundColor: data.patternList.includes(item) ? data.patternColor : data.cardColor }" @click.stop="(event) => updatePatternList(event, item)" />
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
<!-- eslint-disable vue/no-parsing-error -->
|
<!-- eslint-disable vue/no-parsing-error -->
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted } from 'vue';
|
import type { IPersonConfig } from '@/types/storeType'
|
||||||
import useStore from '@/store'
|
|
||||||
import { IPersonConfig } from '@/types/storeType';
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import * as XLSX from 'xlsx'
|
|
||||||
import { readFileBinary } from '@/utils/file'
|
|
||||||
import { addOtherInfo } from '@/utils'
|
|
||||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||||
|
import i18n from '@/locales/i18n'
|
||||||
|
import useStore from '@/store'
|
||||||
|
import { addOtherInfo } from '@/utils'
|
||||||
|
import { readFileBinary } from '@/utils/file'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import * as XLSX from 'xlsx'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const personConfig = useStore().personConfig
|
const personConfig = useStore().personConfig
|
||||||
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
||||||
const limitType = '.xlsx,.xls'
|
const limitType = '.xlsx,.xls'
|
||||||
@@ -17,176 +20,200 @@ const limitType = '.xlsx,.xls'
|
|||||||
const resetDataDialog = ref()
|
const resetDataDialog = ref()
|
||||||
const delAllDataDialog = ref()
|
const delAllDataDialog = ref()
|
||||||
|
|
||||||
const handleFileChange = async (e: Event) => {
|
async function handleFileChange(e: Event) {
|
||||||
let dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
|
const dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
|
||||||
let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
|
const workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
|
||||||
let workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
const workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
||||||
const excelData = XLSX.utils.sheet_to_json(workSheet)
|
const excelData = XLSX.utils.sheet_to_json(workSheet)
|
||||||
const allData = addOtherInfo(excelData);
|
const allData = addOtherInfo(excelData)
|
||||||
personConfig.resetPerson()
|
personConfig.resetPerson()
|
||||||
personConfig.addNotPersonList(allData)
|
personConfig.addNotPersonList(allData)
|
||||||
}
|
}
|
||||||
const exportData = () => {
|
function exportData() {
|
||||||
let data = JSON.parse(JSON.stringify(allPersonList.value))
|
let data = JSON.parse(JSON.stringify(allPersonList.value))
|
||||||
// 排除一些字段
|
// 排除一些字段
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
delete data[i].x
|
delete data[i].x
|
||||||
delete data[i].y
|
delete data[i].y
|
||||||
delete data[i].id
|
delete data[i].id
|
||||||
delete data[i].createTime
|
delete data[i].createTime
|
||||||
delete data[i].updateTime
|
delete data[i].updateTime
|
||||||
delete data[i].prizeId
|
delete data[i].prizeId
|
||||||
// 修改字段名称
|
// 修改字段名称
|
||||||
if (data[i].isWin) {
|
if (data[i].isWin) {
|
||||||
data[i].isWin = '是'
|
data[i].isWin = i18n.global.t('data.yes')
|
||||||
} else {
|
|
||||||
data[i].isWin = '否'
|
|
||||||
}
|
|
||||||
// 格式化数组为
|
|
||||||
data[i].prizeTime = data[i].prizeTime.join(',')
|
|
||||||
data[i].prizeName = data[i].prizeName.join(',')
|
|
||||||
}
|
}
|
||||||
let dataString = JSON.stringify(data)
|
else {
|
||||||
dataString = dataString
|
data[i].isWin = i18n.global.t('data.no')
|
||||||
.replaceAll(/uid/g, '编号')
|
|
||||||
.replaceAll(/isWin/g, '是否中奖')
|
|
||||||
.replaceAll(/department/g, '部门')
|
|
||||||
.replaceAll(/name/g, '姓名')
|
|
||||||
.replaceAll(/identity/g, '身份')
|
|
||||||
.replaceAll(/prizeName/g, '获奖')
|
|
||||||
.replaceAll(/prizeTime/g, '获奖时间')
|
|
||||||
|
|
||||||
data = JSON.parse(dataString)
|
|
||||||
|
|
||||||
if (data.length > 0) {
|
|
||||||
const dataBinary = XLSX.utils.json_to_sheet(data)
|
|
||||||
const dataBinaryBinary = XLSX.utils.book_new()
|
|
||||||
XLSX.utils.book_append_sheet(dataBinaryBinary, dataBinary, 'Sheet1')
|
|
||||||
XLSX.writeFile(dataBinaryBinary, 'data.xlsx')
|
|
||||||
}
|
}
|
||||||
|
// 格式化数组为
|
||||||
|
data[i].prizeTime = data[i].prizeTime.join(',')
|
||||||
|
data[i].prizeName = data[i].prizeName.join(',')
|
||||||
|
}
|
||||||
|
let dataString = JSON.stringify(data)
|
||||||
|
dataString = dataString
|
||||||
|
.replaceAll(/uid/g, i18n.global.t('data.number'))
|
||||||
|
.replaceAll(/isWin/g, i18n.global.t('data.isWin'))
|
||||||
|
.replaceAll(/department/g, i18n.global.t('data.department'))
|
||||||
|
.replaceAll(/name/g, i18n.global.t('data.name'))
|
||||||
|
.replaceAll(/identity/g, i18n.global.t('data.identity'))
|
||||||
|
.replaceAll(/prizeName/g, i18n.global.t('data.prizeName'))
|
||||||
|
.replaceAll(/prizeTime/g, i18n.global.t('data.prizeTime'))
|
||||||
|
|
||||||
|
data = JSON.parse(dataString)
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
const dataBinary = XLSX.utils.json_to_sheet(data)
|
||||||
|
const dataBinaryBinary = XLSX.utils.book_new()
|
||||||
|
XLSX.utils.book_append_sheet(dataBinaryBinary, dataBinary, 'Sheet1')
|
||||||
|
XLSX.writeFile(dataBinaryBinary, 'data.xlsx')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetData = () => {
|
function resetData() {
|
||||||
personConfig.resetAlreadyPerson()
|
personConfig.resetAlreadyPerson()
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteAll = () => {
|
function deleteAll() {
|
||||||
personConfig.deleteAllPerson()
|
personConfig.deleteAllPerson()
|
||||||
}
|
}
|
||||||
|
|
||||||
const delPersonItem = (row: IPersonConfig) => {
|
function delPersonItem(row: IPersonConfig) {
|
||||||
personConfig.deletePerson(row)
|
personConfig.deletePerson(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
{
|
{
|
||||||
label: '编号',
|
label: i18n.global.t('data.number'),
|
||||||
props: 'uid',
|
props: 'uid',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('data.name'),
|
||||||
|
props: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('data.department'),
|
||||||
|
props: 'department',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('data.identity'),
|
||||||
|
props: 'identity',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: i18n.global.t('data.isWin'),
|
||||||
|
props: 'isWin',
|
||||||
|
formatValue(row: IPersonConfig) {
|
||||||
|
return row.isWin ? i18n.global.t('data.yes') : i18n.global.t('data.no')
|
||||||
},
|
},
|
||||||
{
|
},
|
||||||
label: '姓名',
|
{
|
||||||
props: 'name',
|
label: i18n.global.t('data.operation'),
|
||||||
},
|
actions: [
|
||||||
{
|
// {
|
||||||
label: '部门',
|
// label: '编辑',
|
||||||
props: 'department',
|
// type: 'btn-info',
|
||||||
},
|
// onClick: (row: any) => {
|
||||||
{
|
// delPersonItem(row)
|
||||||
label: '身份',
|
// }
|
||||||
props: 'identity',
|
// },
|
||||||
},
|
{
|
||||||
{
|
label: i18n.global.t('data.delete'),
|
||||||
label: '是否已中奖',
|
type: 'btn-error',
|
||||||
props: 'isWin',
|
onClick: (row: IPersonConfig) => {
|
||||||
formatValue(row: IPersonConfig) {
|
delPersonItem(row)
|
||||||
return row.isWin ? '是' : '否'
|
},
|
||||||
}
|
},
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '操作',
|
|
||||||
actions: [
|
|
||||||
// {
|
|
||||||
// label: '编辑',
|
|
||||||
// type: 'btn-info',
|
|
||||||
// onClick: (row: any) => {
|
|
||||||
// delPersonItem(row)
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'btn-error',
|
|
||||||
onClick: (row: IPersonConfig) => {
|
|
||||||
delPersonItem(row)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<dialog id="my_modal_1" ref="resetDataDialog" class="border-none modal">
|
<dialog id="my_modal_1" ref="resetDataDialog" class="border-none modal">
|
||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<h3 class="text-lg font-bold">提示!</h3>
|
<h3 class="text-lg font-bold">
|
||||||
<p class="py-4">该操作会清空人员中奖信息,是否继续?</p>
|
{{ t('dialog.titleTip') }}
|
||||||
<div class="modal-action">
|
</h3>
|
||||||
<form method="dialog" class="flex gap-3">
|
<p class="py-4">
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
{{ t('dialog.dialogResetWinner') }}
|
||||||
<button class="btn" @click="resetDataDialog.close()">取消</button>
|
</p>
|
||||||
<button class="btn" @click="resetData">确定</button>
|
<div class="modal-action">
|
||||||
</form>
|
<form method="dialog" class="flex gap-3">
|
||||||
</div>
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
</div>
|
<button class="btn" @click="resetDataDialog.close()">
|
||||||
</dialog>
|
{{ t('button.cancel') }}
|
||||||
<dialog id="my_modal_1" ref="delAllDataDialog" class="border-none modal">
|
</button>
|
||||||
<div class="modal-box">
|
<button class="btn" @click="resetData">
|
||||||
<h3 class="text-lg font-bold">提示!</h3>
|
{{ t('button.confirm') }}
|
||||||
<p class="py-4">该操作会删除所有人员数据,是否继续?</p>
|
</button>
|
||||||
<div class="modal-action">
|
</form>
|
||||||
<form method="dialog" class="flex gap-3">
|
</div>
|
||||||
<!-- if there is a button in form, it will close the modal -->
|
|
||||||
<button class="btn" @click="delAllDataDialog.close()">取消</button>
|
|
||||||
<button class="btn" @click="deleteAll">确定</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</dialog>
|
|
||||||
<div class="min-w-1000px">
|
|
||||||
|
|
||||||
<h2>人员管理</h2>
|
|
||||||
<div class="flex gap-3">
|
|
||||||
<button class="btn btn-error btn-sm" @click="delAllDataDialog.showModal()">全部删除</button>
|
|
||||||
<div class="tooltip tooltip-bottom" data-tip="下载文件后,请在excel中填写数据,并保存为xlsx格式">
|
|
||||||
<a class="no-underline btn btn-secondary btn-sm" download="人口登记表.xlsx" target="_blank"
|
|
||||||
href="/log-lottery/人口登记表.xlsx">下载模板</a>
|
|
||||||
</div>
|
|
||||||
<div class="">
|
|
||||||
<label for="explore">
|
|
||||||
|
|
||||||
<div class="tooltip tooltip-bottom" data-tip="上传修改好的excel文件">
|
|
||||||
<input type="file" class="" id="explore" style="display: none" @change="handleFileChange"
|
|
||||||
:accept="limitType" />
|
|
||||||
|
|
||||||
<span class="btn btn-primary btn-sm">导入人员数据</span>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<!-- <button class="btn btn-primary btn-sm">上传excel</button> -->
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-error btn-sm" @click="resetDataDialog.showModal()">重置人员数据</button>
|
|
||||||
<button class="btn btn-accent btn-sm" @click="exportData">导出结果</button>
|
|
||||||
<div>
|
|
||||||
<span>中奖人数:</span>
|
|
||||||
<span>{{ alreadyPersonList.length }}</span>
|
|
||||||
<span> / </span>
|
|
||||||
<span>{{ allPersonList.length }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<DaiysuiTable :tableColumns="tableColumns" :data="allPersonList"></DaiysuiTable>
|
|
||||||
</div>
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<dialog id="my_modal_1" ref="delAllDataDialog" class="border-none modal">
|
||||||
|
<div class="modal-box">
|
||||||
|
<h3 class="text-lg font-bold">
|
||||||
|
{{ t('dialog.titleTip') }}
|
||||||
|
</h3>
|
||||||
|
<p class="py-4">
|
||||||
|
{{ t('dialog.dialogDelAllPerson') }}
|
||||||
|
</p>
|
||||||
|
<div class="modal-action">
|
||||||
|
<form method="dialog" class="flex gap-3">
|
||||||
|
<!-- if there is a button in form, it will close the modal -->
|
||||||
|
<button class="btn" @click="delAllDataDialog.close()">
|
||||||
|
{{ t('button.cancel') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn" @click="deleteAll">
|
||||||
|
{{ t('button.confirm') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<div class="min-w-1000px">
|
||||||
|
<h2>{{ t('viewTitle.personManagement') }}</h2>
|
||||||
|
<div class="flex gap-3">
|
||||||
|
<button class="btn btn-error btn-sm" @click="delAllDataDialog.showModal()">
|
||||||
|
{{ t('button.allDelete') }}
|
||||||
|
</button>
|
||||||
|
<div class="tooltip tooltip-bottom" :data-tip="t('tooltip.downloadTemplateTip')">
|
||||||
|
<a
|
||||||
|
class="no-underline btn btn-secondary btn-sm" :download="t('data.xlsxName')" target="_blank"
|
||||||
|
:href="`/log-lottery/${t('data.xlsxName')}`"
|
||||||
|
>{{ t('button.downloadTemplate') }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<label for="explore">
|
||||||
|
|
||||||
|
<div class="tooltip tooltip-bottom" :data-tip="t('tooltip.uploadExcelTip')">
|
||||||
|
<input
|
||||||
|
id="explore" type="file" class="" style="display: none" :accept="limitType"
|
||||||
|
@change="handleFileChange"
|
||||||
|
>
|
||||||
|
|
||||||
|
<span class="btn btn-primary btn-sm">{{ t('button.importData') }}</span>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-error btn-sm" @click="resetDataDialog.showModal()">
|
||||||
|
{{ t('button.resetData') }}
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-accent btn-sm" @click="exportData">
|
||||||
|
{{ t('button.exportResult') }}
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
<span>{{ t('table.luckyPeopleNumber') }}:</span>
|
||||||
|
<span>{{ alreadyPersonList.length }}</span>
|
||||||
|
<span> / </span>
|
||||||
|
<span>{{ allPersonList.length }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DaiysuiTable :table-columns="tableColumns" :data="allPersonList" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
<!-- eslint-disable vue/no-parsing-error -->
|
<!-- eslint-disable vue/no-parsing-error -->
|
||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref } from 'vue';
|
import type { IPersonConfig } from '@/types/storeType'
|
||||||
import useStore from '@/store'
|
|
||||||
import { IPersonConfig } from '@/types/storeType';
|
|
||||||
import { storeToRefs } from 'pinia';
|
|
||||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||||
|
import i18n from '@/locales/i18n'
|
||||||
|
import useStore from '@/store'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const personConfig = useStore().personConfig
|
const personConfig = useStore().personConfig
|
||||||
|
|
||||||
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
|
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
|
||||||
@@ -13,119 +16,116 @@ const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: already
|
|||||||
// alreadyPersonList
|
// alreadyPersonList
|
||||||
// )
|
// )
|
||||||
|
|
||||||
|
|
||||||
// const deleteAll = () => {
|
// const deleteAll = () => {
|
||||||
// personConfig.deleteAllPerson()
|
// personConfig.deleteAllPerson()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
const isDetail = ref(false)
|
const isDetail = ref(false)
|
||||||
const handleMoveNotPerson = (row: IPersonConfig) => {
|
function handleMoveNotPerson(row: IPersonConfig) {
|
||||||
personConfig.moveAlreadyToNot(row)
|
personConfig.moveAlreadyToNot(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableColumnsList = [
|
const tableColumnsList = [
|
||||||
{
|
{
|
||||||
label: '编号',
|
label: i18n.global.t('data.number'),
|
||||||
props: 'uid',
|
props: 'uid',
|
||||||
sort: true
|
sort: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '姓名',
|
label: i18n.global.t('data.number'),
|
||||||
props: 'name',
|
props: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '部门',
|
label: i18n.global.t('data.department'),
|
||||||
props: 'department',
|
props: 'department',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '身份',
|
label: i18n.global.t('data.identity'),
|
||||||
props: 'identity',
|
props: 'identity',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '奖品',
|
label: i18n.global.t('data.prizeName'),
|
||||||
props: 'prizeName',
|
props: 'prizeName',
|
||||||
sort: true
|
sort: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '操作',
|
label: i18n.global.t('data.operation'),
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: '移入未中奖名单',
|
label: i18n.global.t('data.removePerson'),
|
||||||
type: 'btn-info',
|
type: 'btn-info',
|
||||||
onClick: (row: IPersonConfig) => {
|
onClick: (row: IPersonConfig) => {
|
||||||
handleMoveNotPerson(row)
|
handleMoveNotPerson(row)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
const tableColumnsDetail = [
|
const tableColumnsDetail = [
|
||||||
{
|
{
|
||||||
label: '编号',
|
label: i18n.global.t('data.number'),
|
||||||
props: 'uid',
|
props: 'uid',
|
||||||
sort: true
|
sort: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '姓名',
|
label: i18n.global.t('data.number'),
|
||||||
props: 'name',
|
props: 'name',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '部门',
|
label: i18n.global.t('data.department'),
|
||||||
props: 'department',
|
props: 'department',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '身份',
|
label: i18n.global.t('data.identity'),
|
||||||
props: 'identity',
|
props: 'identity',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '奖品',
|
label: i18n.global.t('data.prizeName'),
|
||||||
props: 'prizeName',
|
props: 'prizeName',
|
||||||
sort: true
|
sort: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '中奖时间',
|
label: i18n.global.t('data.prizeTime'),
|
||||||
props: 'prizeTime',
|
props: 'prizeTime',
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '操作',
|
label: i18n.global.t('data.operation'),
|
||||||
actions: [
|
actions: [
|
||||||
{
|
{
|
||||||
label: '移入未中奖名单',
|
label: i18n.global.t('data.removePerson'),
|
||||||
type: 'btn-info',
|
type: 'btn-info',
|
||||||
onClick: (row: IPersonConfig) => {
|
onClick: (row: IPersonConfig) => {
|
||||||
handleMoveNotPerson(row)
|
handleMoveNotPerson(row)
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-y-auto">
|
<div class="overflow-y-auto">
|
||||||
|
<h2>{{ t('viewTitle.winnerManagement') }}</h2>
|
||||||
<h2>已中奖人员管理</h2>
|
<div class="flex items-center justify-start gap-10">
|
||||||
<div class="flex items-center justify-start gap-10">
|
<div>
|
||||||
<!-- <button class="btn btn-error btn-sm" @click="deleteAll">全部删除</button> -->
|
<span>{{ t('table.luckyPeopleNumber') }}:</span>
|
||||||
<div>
|
<span>{{ alreadyPersonList.length }}</span>
|
||||||
<span>中奖人数:</span>
|
</div>
|
||||||
<span>{{ alreadyPersonList.length }}</span>
|
<div class="flex flex-col">
|
||||||
</div>
|
<div class="form-control">
|
||||||
<div class="flex flex-col">
|
<label class="cursor-pointer label">
|
||||||
<div class="form-control">
|
<span class="label-text">{{ t('table.detail') }}:</span>
|
||||||
<label class="cursor-pointer label">
|
<input v-model="isDetail" type="checkbox" class="border-solid toggle toggle-primary border-1">
|
||||||
<span class="label-text">详细信息:</span>
|
</label>
|
||||||
<input type="checkbox" class="border-solid toggle toggle-primary border-1" v-model="isDetail" />
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<DaiysuiTable v-if="!isDetail" :tableColumns="tableColumnsList" :data="alreadyPersonList"></DaiysuiTable>
|
</div>
|
||||||
|
|
||||||
<DaiysuiTable v-if="isDetail" :tableColumns="tableColumnsDetail" :data="alreadyPersonDetail"></DaiysuiTable>
|
|
||||||
</div>
|
</div>
|
||||||
|
<DaiysuiTable v-if="!isDetail" :table-columns="tableColumnsList" :data="alreadyPersonList" />
|
||||||
|
|
||||||
|
<DaiysuiTable v-if="isDetail" :table-columns="tableColumnsDetail" :data="alreadyPersonDetail" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<router-view></router-view>
|
<router-view />
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import type { IPrizeConfig } from '@/types/storeType'
|
||||||
import useStore from '@/store'
|
|
||||||
import { IPrizeConfig } from '@/types/storeType'
|
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import localforage from 'localforage'
|
|
||||||
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
||||||
|
import i18n from '@/locales/i18n'
|
||||||
|
import useStore from '@/store'
|
||||||
|
import localforage from 'localforage'
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
import { onMounted, ref, watch } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const imageDbStore = localforage.createInstance({
|
const imageDbStore = localforage.createInstance({
|
||||||
name: 'imgStore'
|
name: 'imgStore',
|
||||||
})
|
})
|
||||||
const prizeConfig = useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
@@ -19,243 +22,266 @@ const imgList = ref<any[]>([])
|
|||||||
|
|
||||||
const selectedPrize = ref<IPrizeConfig | null>()
|
const selectedPrize = ref<IPrizeConfig | null>()
|
||||||
|
|
||||||
const addPrize = () => {
|
function addPrize() {
|
||||||
const defaultPrizeCOnfig: IPrizeConfig = {
|
const defaultPrizeCOnfig: IPrizeConfig = {
|
||||||
id: new Date().getTime().toString(),
|
id: new Date().getTime().toString(),
|
||||||
name: '奖项',
|
name: i18n.global.t('data.prizeName'),
|
||||||
sort: 0,
|
sort: 0,
|
||||||
isAll: false,
|
isAll: false,
|
||||||
count: 1,
|
count: 1,
|
||||||
|
isUsedCount: 0,
|
||||||
|
picture: {
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
},
|
||||||
|
separateCount: {
|
||||||
|
enable: false,
|
||||||
|
countList: [],
|
||||||
|
},
|
||||||
|
desc: '',
|
||||||
|
isUsed: false,
|
||||||
|
isShow: true,
|
||||||
|
frequency: 1,
|
||||||
|
}
|
||||||
|
prizeConfig.addPrizeConfig(defaultPrizeCOnfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectPrize(item: IPrizeConfig) {
|
||||||
|
selectedPrize.value = item
|
||||||
|
selectedPrize.value.isUsedCount = 0
|
||||||
|
selectedPrize.value.isUsed = false
|
||||||
|
|
||||||
|
if (selectedPrize.value.separateCount.countList.length > 1) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
selectedPrize.value.separateCount = {
|
||||||
|
enable: true,
|
||||||
|
countList: [
|
||||||
|
{
|
||||||
|
id: '0',
|
||||||
|
count: item.count,
|
||||||
isUsedCount: 0,
|
isUsedCount: 0,
|
||||||
picture: {
|
},
|
||||||
id: '',
|
],
|
||||||
name: '',
|
}
|
||||||
url: ''
|
|
||||||
},
|
|
||||||
separateCount: {
|
|
||||||
enable: false,
|
|
||||||
countList: []
|
|
||||||
},
|
|
||||||
desc: '',
|
|
||||||
isUsed: false,
|
|
||||||
isShow: true,
|
|
||||||
frequency: 1,
|
|
||||||
}
|
|
||||||
prizeConfig.addPrizeConfig(defaultPrizeCOnfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectPrize = (item: IPrizeConfig) => {
|
function changePrizeStatus(item: IPrizeConfig) {
|
||||||
selectedPrize.value = item
|
// if (item.isUsed == true) {
|
||||||
selectedPrize.value.isUsedCount = 0
|
// item.isUsedCount = 0;
|
||||||
selectedPrize.value.isUsed = false
|
// if (item.separateCount && item.separateCount.countList.length) {
|
||||||
|
// item.separateCount.countList.forEach((countItem: any) => {
|
||||||
if (selectedPrize.value.separateCount.countList.length > 1) {
|
// countItem.isUsedCount = 0;
|
||||||
return
|
// })
|
||||||
}
|
// }
|
||||||
selectedPrize.value.separateCount = {
|
// }
|
||||||
enable: true,
|
// else {
|
||||||
countList: [
|
// item.isUsedCount = item.count;
|
||||||
{
|
// if (item.separateCount && item.separateCount.countList.length) {
|
||||||
id: '0',
|
// item.separateCount.countList.forEach((countItem: any) => {
|
||||||
count: item.count,
|
// countItem.isUsedCount = countItem.count;
|
||||||
isUsedCount: 0,
|
// })
|
||||||
}
|
// }
|
||||||
]
|
// }
|
||||||
}
|
item.isUsed ? item.isUsedCount = 0 : item.isUsedCount = item.count
|
||||||
|
item.separateCount.countList = []
|
||||||
|
item.isUsed = !item.isUsed
|
||||||
}
|
}
|
||||||
|
|
||||||
const changePrizeStatus = (item: IPrizeConfig) => {
|
function changePrizePerson(item: IPrizeConfig) {
|
||||||
// if (item.isUsed == true) {
|
let indexPrize = -1
|
||||||
// item.isUsedCount = 0;
|
for (let i = 0; i < prizeList.value.length; i++) {
|
||||||
// if (item.separateCount && item.separateCount.countList.length) {
|
if (prizeList.value[i].id === item.id) {
|
||||||
// item.separateCount.countList.forEach((countItem: any) => {
|
indexPrize = i
|
||||||
// countItem.isUsedCount = 0;
|
break
|
||||||
// })
|
}
|
||||||
// }
|
}
|
||||||
// }
|
if (indexPrize > -1) {
|
||||||
// else {
|
prizeList.value[indexPrize].separateCount.countList = []
|
||||||
// item.isUsedCount = item.count;
|
prizeList.value[indexPrize].isUsed ? prizeList.value[indexPrize].isUsedCount = prizeList.value[indexPrize].count : prizeList.value[indexPrize].isUsedCount = 0
|
||||||
// if (item.separateCount && item.separateCount.countList.length) {
|
}
|
||||||
// item.separateCount.countList.forEach((countItem: any) => {
|
}
|
||||||
// countItem.isUsedCount = countItem.count;
|
function submitData(value: any) {
|
||||||
// })
|
selectedPrize.value!.separateCount.countList = value
|
||||||
// }
|
selectedPrize.value = null
|
||||||
// }
|
}
|
||||||
item.isUsed?item.isUsedCount=0:item.isUsedCount=item.count;
|
function resetDefault() {
|
||||||
item.separateCount.countList = []
|
prizeConfig.resetDefault()
|
||||||
item.isUsed = !item.isUsed
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const changePrizePerson = (item: IPrizeConfig) => {
|
async function getImageDbStore() {
|
||||||
let indexPrize = -1;
|
const keys = await imageDbStore.keys()
|
||||||
for (let i = 0; i < prizeList.value.length; i++) {
|
if (keys.length > 0) {
|
||||||
if (prizeList.value[i].id == item.id) {
|
imageDbStore.iterate((value, key) => {
|
||||||
indexPrize = i;
|
imgList.value.push({
|
||||||
break;
|
key,
|
||||||
}
|
value,
|
||||||
}
|
})
|
||||||
if (indexPrize > -1) {
|
})
|
||||||
prizeList.value[indexPrize].separateCount.countList = []
|
}
|
||||||
prizeList.value[indexPrize].isUsed?prizeList.value[indexPrize].isUsedCount=prizeList.value[indexPrize].count:prizeList.value[indexPrize].isUsedCount=0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const submitData = (value: any) => {
|
|
||||||
selectedPrize.value!.separateCount.countList = value;
|
|
||||||
selectedPrize.value = null
|
|
||||||
}
|
|
||||||
const resetDefault = () => {
|
|
||||||
prizeConfig.resetDefault()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getImageDbStore = async () => {
|
function sort(item: IPrizeConfig, isUp: number) {
|
||||||
const keys = await imageDbStore.keys()
|
const itemIndex = prizeList.value.indexOf(item)
|
||||||
if (keys.length > 0) {
|
if (isUp === 1) {
|
||||||
imageDbStore.iterate((value, key) => {
|
prizeList.value.splice(itemIndex, 1)
|
||||||
imgList.value.push({
|
prizeList.value.splice(itemIndex - 1, 0, item)
|
||||||
key,
|
}
|
||||||
value
|
else {
|
||||||
})
|
prizeList.value.splice(itemIndex, 1)
|
||||||
})
|
prizeList.value.splice(itemIndex + 1, 0, item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function delItem(item: IPrizeConfig) {
|
||||||
const sort = (item: IPrizeConfig, isUp: number) => {
|
prizeConfig.deletePrizeConfig(item.id)
|
||||||
const itemIndex = prizeList.value.indexOf(item)
|
|
||||||
if (isUp == 1) {
|
|
||||||
prizeList.value.splice(itemIndex, 1)
|
|
||||||
prizeList.value.splice(itemIndex - 1, 0, item)
|
|
||||||
} else {
|
|
||||||
prizeList.value.splice(itemIndex, 1)
|
|
||||||
prizeList.value.splice(itemIndex + 1, 0, item)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const delItem = (item: IPrizeConfig) => {
|
async function delAll() {
|
||||||
prizeConfig.deletePrizeConfig(item.id)
|
await prizeConfig.deleteAllPrizeConfig()
|
||||||
}
|
|
||||||
const delAll = async () => {
|
|
||||||
await prizeConfig.deleteAllPrizeConfig()
|
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getImageDbStore()
|
getImageDbStore()
|
||||||
})
|
})
|
||||||
watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
watch(() => prizeList.value, (val: IPrizeConfig[]) => {
|
||||||
prizeConfig.setPrizeConfig(val)
|
prizeConfig.setPrizeConfig(val)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h2>奖项配置</h2>
|
<h2>{{ t('viewTitle.prizeManagement') }}</h2>
|
||||||
<div class="flex w-full gap-3">
|
<div class="flex w-full gap-3">
|
||||||
<button class="btn btn-info btn-sm" @click="addPrize">添加</button>
|
<button class="btn btn-info btn-sm" @click="addPrize">
|
||||||
<button class="btn btn-info btn-sm" @click="resetDefault">默认列表</button>
|
{{ t('button.add') }}
|
||||||
<button class="btn btn-error btn-sm" @click="delAll">全部删除</button>
|
</button>
|
||||||
|
<button class="btn btn-info btn-sm" @click="resetDefault">
|
||||||
</div>
|
{{ t('button.resetDefault') }}
|
||||||
<div role="alert" class="w-full my-4 alert alert-info">
|
</button>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-6 h-6 stroke-current shrink-0">
|
<button class="btn btn-error btn-sm" @click="delAll">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
{{ t('button.allDelete') }}
|
||||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
</button>
|
||||||
</svg>
|
|
||||||
<span>进行操作可能会重置数据,请谨慎操作</span>
|
|
||||||
</div>
|
|
||||||
<ul class="p-0 m-0">
|
|
||||||
<li v-for="item in prizeList" :key="item.id" class="flex gap-10"
|
|
||||||
:class="currentPrize.id == item.id ? 'border-1 border-dotted rounded-xl' : null">
|
|
||||||
<label class="max-w-xs mb-10 form-control">
|
|
||||||
<!-- 向上向下 -->
|
|
||||||
<div class="flex flex-col items-center gap-2 pt-5">
|
|
||||||
<svg-icon class="cursor-pointer hover:text-blue-400"
|
|
||||||
:class="prizeList.indexOf(item) == 0 ? 'opacity-0 cursor-default' : ''" name="up"
|
|
||||||
@click="sort(item, 1)"></svg-icon>
|
|
||||||
<svg-icon class="cursor-pointer hover:text-blue-400" name="down" @click="sort(item, 0)"
|
|
||||||
:class="prizeList.indexOf(item) == prizeList.length - 1 ? 'opacity-0 cursor-default' : ''"></svg-icon>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<label class="w-1/2 max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">名称</span>
|
|
||||||
</div>
|
|
||||||
<input type="text" v-model="item.name" placeholder="名称"
|
|
||||||
class="w-full max-w-xs input-sm input input-bordered" />
|
|
||||||
</label>
|
|
||||||
<label class="w-1/2 max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">全员参加</span>
|
|
||||||
</div>
|
|
||||||
<input type="checkbox" :checked="item.isAll" @change="item.isAll = !item.isAll"
|
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
|
||||||
</label>
|
|
||||||
<label class="w-1/2 max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">抽奖人数</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="item.count" placeholder="获奖人数" @change="changePrizePerson(item)"
|
|
||||||
class="w-full max-w-xs p-0 m-0 input-sm input input-bordered" />
|
|
||||||
<div class="tooltip tooltip-bottom" :data-tip="'已抽取:' + item.isUsedCount + '/' + item.count">
|
|
||||||
<progress class="w-full progress" :value="item.isUsedCount" :max="item.count"></progress>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<!-- <label class="w-1/2 max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">已获奖人数</span>
|
|
||||||
</div>
|
|
||||||
<input disabled type="number" v-model="item.isUsedCount" placeholder="获奖人数"
|
|
||||||
class="w-full max-w-xs input-sm input input-bordered" />
|
|
||||||
</label> -->
|
|
||||||
<label class="w-1/2 max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">已抽取</span>
|
|
||||||
</div>
|
|
||||||
<input type="checkbox" :checked="item.isUsed" @change="changePrizeStatus(item)"
|
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">图片</span>
|
|
||||||
</div>
|
|
||||||
<select class="w-full max-w-xs select select-warning select-sm" v-model="item.picture">
|
|
||||||
<option v-if="item.picture.id" :value="{ id: '', name: '', url: '' }">❌</option>
|
|
||||||
<option disabled selected>选择一张图片</option>
|
|
||||||
<option v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{ picItem.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs mb-10 form-control" v-if="item.separateCount">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">单次抽取个数</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-start w-full h-full" @click="selectPrize(item)">
|
|
||||||
<ul class="flex flex-wrap w-full h-full gap-1 p-0 pt-1 m-0 cursor-pointer"
|
|
||||||
v-if="item.separateCount.countList.length">
|
|
||||||
<li class="relative flex items-center justify-center w-8 h-8 bg-slate-600/60 separated"
|
|
||||||
v-for="se in item.separateCount.countList" :key="se.id">
|
|
||||||
<div class="flex items-center justify-center w-full h-full tooltip"
|
|
||||||
:data-tip="'已抽取:' + se.isUsedCount + '/' + se.count">
|
|
||||||
<div class="absolute left-0 z-50 h-full bg-blue-300/80"
|
|
||||||
:style="`width:${se.isUsedCount * 100 / se.count}%`"></div>
|
|
||||||
<span>{{ se.count }}</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button v-else class="btn btn-secondary btn-xs">设置</button>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<label class="w-full max-w-xs mb-10 form-control">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">操作</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex gap-2">
|
|
||||||
<button class="btn btn-error btn-sm" @click="delItem(item)">删除</button>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<EditSeparateDialog :totalNumber="selectedPrize?.count" :separated-number="selectedPrize?.separateCount.countList"
|
|
||||||
@submitData="submitData" />
|
|
||||||
</div>
|
</div>
|
||||||
|
<div role="alert" class="w-full my-4 alert alert-info">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" class="w-6 h-6 stroke-current shrink-0">
|
||||||
|
<path
|
||||||
|
stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||||
|
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
<span>{{ t('dialog.tipResetPrize') }}</span>
|
||||||
|
</div>
|
||||||
|
<ul class="p-0 m-0">
|
||||||
|
<li
|
||||||
|
v-for="item in prizeList" :key="item.id" class="flex gap-10"
|
||||||
|
:class="currentPrize.id === item.id ? 'border-1 border-dotted rounded-xl' : null"
|
||||||
|
>
|
||||||
|
<label class="max-w-xs mb-10 form-control">
|
||||||
|
<!-- 向上向下 -->
|
||||||
|
<div class="flex flex-col items-center gap-2 pt-5">
|
||||||
|
<svg-icon
|
||||||
|
class="cursor-pointer hover:text-blue-400"
|
||||||
|
:class="prizeList.indexOf(item) === 0 ? 'opacity-0 cursor-default' : ''" name="up"
|
||||||
|
@click="sort(item, 1)"
|
||||||
|
/>
|
||||||
|
<svg-icon
|
||||||
|
class="cursor-pointer hover:text-blue-400" name="down" :class="prizeList.indexOf(item) === prizeList.length - 1 ? 'opacity-0 cursor-default' : ''"
|
||||||
|
@click="sort(item, 0)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="w-1/2 max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.prizeName') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="item.name" type="text" :placeholder="t('placeHolder.name')"
|
||||||
|
class="w-full max-w-xs input-sm input input-bordered"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label class="w-1/2 max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.fullParticipation') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="checkbox" :checked="item.isAll" class="mt-2 border-solid checkbox checkbox-secondary border-1"
|
||||||
|
@change="item.isAll = !item.isAll"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label class="w-1/2 max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.numberParticipants') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
v-model="item.count" type="number" :placeholder="t('placeHolder.winnerCount')" class="w-full max-w-xs p-0 m-0 input-sm input input-bordered"
|
||||||
|
@change="changePrizePerson(item)"
|
||||||
|
>
|
||||||
|
<div class="tooltip tooltip-bottom" :data-tip="`${t('table.isDone') + item.isUsedCount}/${item.count}`">
|
||||||
|
<progress class="w-full progress" :value="item.isUsedCount" :max="item.count" />
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="w-1/2 max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.isDone') }}</span>
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="checkbox" :checked="item.isUsed" class="mt-2 border-solid checkbox checkbox-secondary border-1"
|
||||||
|
@change="changePrizeStatus(item)"
|
||||||
|
>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.image') }}</span>
|
||||||
|
</div>
|
||||||
|
<select v-model="item.picture" class="w-full max-w-xs select select-warning select-sm">
|
||||||
|
<option v-if="item.picture.id" :value="{ id: '', name: '', url: '' }">❌</option>
|
||||||
|
<option disabled selected>{{ t('table.selectPicture') }}</option>
|
||||||
|
<option v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{ picItem.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label v-if="item.separateCount" class="w-full max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.onceNumber') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-start w-full h-full" @click="selectPrize(item)">
|
||||||
|
<ul
|
||||||
|
v-if="item.separateCount.countList.length"
|
||||||
|
class="flex flex-wrap w-full h-full gap-1 p-0 pt-1 m-0 cursor-pointer"
|
||||||
|
>
|
||||||
|
<li
|
||||||
|
v-for="se in item.separateCount.countList"
|
||||||
|
:key="se.id" class="relative flex items-center justify-center w-8 h-8 bg-slate-600/60 separated"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-center w-full h-full tooltip"
|
||||||
|
:data-tip="`${t('tooltip.doneCount') + se.isUsedCount}/${se.count}`"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute left-0 z-50 h-full bg-blue-300/80"
|
||||||
|
:style="`width:${se.isUsedCount * 100 / se.count}%`"
|
||||||
|
/>
|
||||||
|
<span>{{ se.count }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button v-else class="btn btn-secondary btn-xs">{{ t('button.setting') }}</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="w-full max-w-xs mb-10 form-control">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.operation') }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<button class="btn btn-error btn-sm" @click="delItem(item)">{{ t('button.delete') }}</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<EditSeparateDialog
|
||||||
|
:total-number="selectedPrize?.count" :separated-number="selectedPrize?.separateCount.countList"
|
||||||
|
@submit-data="submitData"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped></style>
|
<style lang='scss' scoped></style>
|
||||||
|
|||||||
@@ -1,25 +1,27 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import {ref,onMounted} from 'vue'
|
import i18n from '@/locales/i18n'
|
||||||
import markdownit from 'markdown-it'
|
import markdownit from 'markdown-it'
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
|
||||||
const md = markdownit()
|
const md = markdownit()
|
||||||
const readmeHtml=ref('')
|
const readmeHtml = ref('')
|
||||||
const readMd=()=>{
|
function readMd() {
|
||||||
fetch('/log-lottery/readme.md')
|
fetch(`/log-lottery/${i18n.global.t('data.readmeName')}`)
|
||||||
.then(res=>res.text())
|
.then(res => res.text())
|
||||||
.then(res=>{
|
.then((res) => {
|
||||||
readmeHtml.value = md.render(res)
|
readmeHtml.value = md.render(res)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
readMd()
|
readMd()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-3/4 mb-10 ml-3">
|
<div class="w-3/4 mb-10 ml-3">
|
||||||
<div class="markdown-body" v-dompurify-html="readmeHtml"></div>
|
<div v-dompurify-html="readmeHtml" class="markdown-body" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,91 +1,97 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useI18n } from 'vue-i18n'
|
||||||
import { configRoutes } from '../../router';
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { configRoutes } from '../../router'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const router = useRouter();
|
const router = useRouter()
|
||||||
const route = useRoute();
|
const route = useRoute()
|
||||||
const menuList = ref<any[]>(configRoutes.children)
|
const menuList = ref<any[]>(configRoutes.children)
|
||||||
|
|
||||||
const cleanMenuList = (menu: any) => {
|
function cleanMenuList(menu: any) {
|
||||||
const newList = menu;
|
const newList = menu
|
||||||
for (let i = 0; i < newList.length; i++) {
|
for (let i = 0; i < newList.length; i++) {
|
||||||
if (newList[i].children) {
|
if (newList[i].children) {
|
||||||
cleanMenuList(newList[i].children);
|
cleanMenuList(newList[i].children)
|
||||||
}
|
|
||||||
if (!newList[i].meta) {
|
|
||||||
newList.splice(i, 1);
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (!newList[i].meta) {
|
||||||
|
newList.splice(i, 1)
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return newList;
|
return newList
|
||||||
}
|
}
|
||||||
|
|
||||||
menuList.value = cleanMenuList(menuList.value);
|
menuList.value = cleanMenuList(menuList.value)
|
||||||
|
|
||||||
const skip = (path: string) => {
|
function skip(path: string) {
|
||||||
router.push(path);
|
router.push(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex min-h-[calc(100%-280px)]">
|
<div class="flex min-h-[calc(100%-280px)]">
|
||||||
<ul class="w-56 m-0 mr-3 menu bg-base-200 pt-14">
|
<ul class="w-56 m-0 mr-3 min-w-56 menu bg-base-200 pt-14">
|
||||||
<li v-for="item in menuList" :key="item.name">
|
<li v-for="item in menuList" :key="item.name">
|
||||||
<details open v-if="item.children">
|
<details v-if="item.children" open>
|
||||||
<summary>{{ item.meta.title }}</summary>
|
<summary>{{ item.meta.title }}</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="subItem in item.children" :key="subItem.name">
|
<li v-for="subItem in item.children" :key="subItem.name">
|
||||||
<details open v-if="subItem.children">
|
<details v-if="subItem.children" open>
|
||||||
<summary>{{ subItem.meta!.title }}</summary>
|
<summary>{{ subItem.meta!.title }}</summary>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="subSubItem in subItem.children" :key="subSubItem.name">
|
<li v-for="subSubItem in subItem.children" :key="subSubItem.name">
|
||||||
<a @click="skip(subItem.path)"
|
<a
|
||||||
:style="subSubItem.name == route.name ? 'background-color:rgba(12,12,12,0.2)' : ''">{{
|
:style="subSubItem.name === route.name ? 'background-color:rgba(12,12,12,0.2)' : ''"
|
||||||
subSubItem.meta!.title }}</a>
|
@click="skip(subItem.path)"
|
||||||
</li>
|
>{{
|
||||||
</ul>
|
subSubItem.meta!.title }}</a>
|
||||||
</details>
|
</li>
|
||||||
<a v-else @click="skip(subItem.path)"
|
</ul>
|
||||||
:style="subItem.name == route.name ? 'background-color:rgba(12,12,12,0.2)' : ''">{{
|
</details>
|
||||||
subItem.meta!.title }}</a>
|
<a
|
||||||
</li>
|
v-else :style="subItem.name === route.name ? 'background-color:rgba(12,12,12,0.2)' : ''"
|
||||||
</ul>
|
@click="skip(subItem.path)"
|
||||||
</details>
|
>{{
|
||||||
<a v-else @click="skip(item.path)"
|
subItem.meta!.title }}</a>
|
||||||
:style="item.name == route.name ? 'background-color:rgba(12,12,12,0.2)' : ''">{{ item.meta!.title }}</a>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<router-view class="mt-5"></router-view>
|
</details>
|
||||||
</div>
|
<a
|
||||||
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
|
v-else :style="item.name === route.name ? 'background-color:rgba(12,12,12,0.2)' : ''"
|
||||||
<nav class="grid grid-flow-col gap-4">
|
@click="skip(item.path)"
|
||||||
<a class="cursor-pointer link link-hover text-inherit" target="_blank" href="https://1kw20.fun">行有不得,反求诸己</a>
|
>{{ item.meta!.title }}</a>
|
||||||
</nav>
|
</li>
|
||||||
<nav>
|
</ul>
|
||||||
<a class="cursor-pointer link link-hover text-inherit" target="_blank" href="https://1kw20.fun">破山中贼易,破心中贼难</a>
|
<router-view class="flex-1 mt-5" />
|
||||||
</nav>
|
</div>
|
||||||
<nav>
|
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
|
||||||
<div class="grid grid-flow-col gap-4">
|
<nav class="grid grid-flow-col gap-4">
|
||||||
<a href="https://github.com/LOG1997/log-lottery" target="_blank" class="cursor-pointer text-inherit">
|
<a class="cursor-pointer link link-hover text-inherit" target="_blank" href="https://1kw20.fun">{{ t('footer.self-reflection') }}</a>
|
||||||
<svg-icon name="github"></svg-icon>
|
</nav>
|
||||||
</a>
|
<nav>
|
||||||
<a href="https://twitter.com/TaborSwift" target="_blank" class="cursor-pointer "><svg-icon name="twitter"></svg-icon></a>
|
<a class="cursor-pointer link link-hover text-inherit" target="_blank" href="https://1kw20.fun">{{ t('footer.thiefEasy') }}</a>
|
||||||
<a href="https://www.instagram.com/log.z1997/" target="_blank" class="cursor-pointer ">
|
</nav>
|
||||||
<svg-icon name="instagram"></svg-icon>
|
<nav>
|
||||||
</a>
|
<div class="grid grid-flow-col gap-4">
|
||||||
</div>
|
<a href="https://github.com/LOG1997/log-lottery" target="_blank" class="cursor-pointer text-inherit">
|
||||||
</nav>
|
<svg-icon name="github" />
|
||||||
<aside>
|
</a>
|
||||||
|
<a href="https://twitter.com/TaborSwift" target="_blank" class="cursor-pointer "><svg-icon name="twitter" /></a>
|
||||||
<p class="p-0 m-0">蜀ICP备2021028666号</p>
|
<a href="https://www.instagram.com/log.z1997/" target="_blank" class="cursor-pointer ">
|
||||||
<p>Copyright © 2024 - All right reserved by Log1997</p>
|
<svg-icon name="instagram" />
|
||||||
</aside>
|
</a>
|
||||||
</footer>
|
</div>
|
||||||
|
</nav>
|
||||||
|
<aside>
|
||||||
|
<p class="p-0 m-0">
|
||||||
|
蜀ICP备2021028666号
|
||||||
|
</p>
|
||||||
|
<p>Copyright © 2024 - All right reserved by Log1997</p>
|
||||||
|
</aside>
|
||||||
|
</footer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn btn-error">打印</button>
|
<button class="btn btn-error">
|
||||||
</div>
|
打印
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted } from 'vue'
|
import type { IPrizeConfig } from '../../types/storeType'
|
||||||
import { storeToRefs } from 'pinia'
|
|
||||||
import useStore from '@/store'
|
|
||||||
|
|
||||||
import ImageSync from '@/components/ImageSync/index.vue'
|
|
||||||
import defaultPrizeImage from '@/assets/images/龙.png'
|
import defaultPrizeImage from '@/assets/images/龙.png'
|
||||||
import { IPrizeConfig } from '../../types/storeType';
|
import ImageSync from '@/components/ImageSync/index.vue'
|
||||||
|
|
||||||
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
import EditSeparateDialog from '@/components/NumberSeparate/EditSeparateDialog.vue'
|
||||||
|
import i18n from '@/locales/i18n'
|
||||||
|
import useStore from '@/store'
|
||||||
|
|
||||||
|
import { storeToRefs } from 'pinia'
|
||||||
|
|
||||||
|
import { onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
const { t } = useI18n()
|
||||||
const prizeConfig = useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const system = useStore().system
|
const system = useStore().system
|
||||||
@@ -21,245 +25,296 @@ const prizeListContainerRef = ref()
|
|||||||
const temporaryPrizeRef = ref()
|
const temporaryPrizeRef = ref()
|
||||||
const selectedPrize = ref<IPrizeConfig | null>()
|
const selectedPrize = ref<IPrizeConfig | null>()
|
||||||
// 获取prizeListRef高度
|
// 获取prizeListRef高度
|
||||||
const getPrizeListHeight = () => {
|
function getPrizeListHeight() {
|
||||||
let height = 200;
|
let height = 200
|
||||||
if (prizeListRef.value) {
|
if (prizeListRef.value) {
|
||||||
height = (prizeListRef.value as HTMLElement).offsetHeight
|
height = (prizeListRef.value as HTMLElement).offsetHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
return height
|
return height
|
||||||
}
|
}
|
||||||
const prizeShow = ref(structuredClone(isShowPrizeList.value))
|
const prizeShow = ref(structuredClone(isShowPrizeList.value))
|
||||||
|
|
||||||
const addTemporaryPrize = () => {
|
function addTemporaryPrize() {
|
||||||
temporaryPrizeRef.value.showModal()
|
temporaryPrizeRef.value.showModal()
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteTemporaryPrize = () => {
|
function deleteTemporaryPrize() {
|
||||||
temporaryPrize.value.isShow = false
|
temporaryPrize.value.isShow = false
|
||||||
prizeConfig.setTemporaryPrize(temporaryPrize.value)
|
prizeConfig.setTemporaryPrize(temporaryPrize.value)
|
||||||
}
|
}
|
||||||
const submitTemporaryPrize = () => {
|
function submitTemporaryPrize() {
|
||||||
if (!temporaryPrize.value.name || !temporaryPrize.value.count) {
|
if (!temporaryPrize.value.name || !temporaryPrize.value.count) {
|
||||||
alert('请填写完整信息')
|
// eslint-disable-next-line no-alert
|
||||||
|
alert(i18n.global.t('error.completeInformation'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
temporaryPrize.value.isShow = true
|
||||||
|
temporaryPrize.value.id = new Date().getTime().toString()
|
||||||
|
prizeConfig.setCurrentPrize(temporaryPrize.value)
|
||||||
|
}
|
||||||
|
function selectPrize(item: IPrizeConfig) {
|
||||||
|
selectedPrize.value = item
|
||||||
|
selectedPrize.value.isUsedCount = 0
|
||||||
|
selectedPrize.value.isUsed = false
|
||||||
|
|
||||||
return
|
if (selectedPrize.value.separateCount.countList.length > 1) {
|
||||||
}
|
return
|
||||||
temporaryPrize.value.isShow = true
|
}
|
||||||
temporaryPrize.value.id=new Date().getTime().toString()
|
selectedPrize.value.separateCount = {
|
||||||
prizeConfig.setCurrentPrize(temporaryPrize.value)
|
enable: true,
|
||||||
|
countList: [
|
||||||
|
{
|
||||||
|
id: '0',
|
||||||
|
count: item.count,
|
||||||
|
isUsedCount: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const selectPrize = (item: IPrizeConfig) => {
|
function submitData(value: any) {
|
||||||
selectedPrize.value = item
|
selectedPrize.value!.separateCount.countList = value
|
||||||
selectedPrize.value.isUsedCount = 0
|
selectedPrize.value = null
|
||||||
selectedPrize.value.isUsed = false
|
}
|
||||||
|
function changePersonCount() {
|
||||||
|
temporaryPrize.value.separateCount.countList = []
|
||||||
|
}
|
||||||
|
function setCurrentPrize() {
|
||||||
|
for (let i = 0; i < localPrizeList.value.length; i++) {
|
||||||
|
if (localPrizeList.value[i].isUsedCount < localPrizeList.value[i].count) {
|
||||||
|
prizeConfig.setCurrentPrize(localPrizeList.value[i])
|
||||||
|
|
||||||
if (selectedPrize.value.separateCount.countList.length > 1) {
|
return
|
||||||
return
|
|
||||||
}
|
}
|
||||||
selectedPrize.value.separateCount = {
|
}
|
||||||
enable: true,
|
|
||||||
countList: [
|
|
||||||
{
|
|
||||||
id: '0',
|
|
||||||
count: item.count,
|
|
||||||
isUsedCount: 0,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const submitData = (value: any) => {
|
|
||||||
selectedPrize.value!.separateCount.countList = value;
|
|
||||||
selectedPrize.value = null
|
|
||||||
}
|
|
||||||
const changePersonCount=()=>{
|
|
||||||
temporaryPrize.value.separateCount.countList=[]
|
|
||||||
}
|
|
||||||
const setCurrentPrize=()=>{
|
|
||||||
for(let i=0;i<localPrizeList.value.length;i++){
|
|
||||||
if(localPrizeList.value[i].isUsedCount<localPrizeList.value[i].count){
|
|
||||||
prizeConfig.setCurrentPrize(localPrizeList.value[i])
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
prizeListContainerRef.value.style.height = getPrizeListHeight() + 'px'
|
prizeListContainerRef.value.style.height = `${getPrizeListHeight()}px`
|
||||||
setCurrentPrize()
|
setCurrentPrize()
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<dialog id="my_modal_1" ref="temporaryPrizeRef" class="border-none modal">
|
<dialog id="my_modal_1" ref="temporaryPrizeRef" class="border-none modal">
|
||||||
<div class="modal-box">
|
<div class="modal-box">
|
||||||
<h3 class="text-lg font-bold">增加临时抽奖</h3>
|
<h3 class="text-lg font-bold">
|
||||||
<div class="flex flex-col gap-3">
|
{{ t('dialog.titleTemporary') }}
|
||||||
<label class="flex w-full max-w-xs">
|
</h3>
|
||||||
<div class="label">
|
<div class="flex flex-col gap-3">
|
||||||
<span class="label-text">名称:</span>
|
<label class="flex w-full max-w-xs">
|
||||||
</div>
|
<div class="label">
|
||||||
<input type="text" v-model="temporaryPrize.name" placeholder="名称"
|
<span class="label-text">{{ t('table.name') }}:</span>
|
||||||
class="max-w-xs input-sm input input-bordered" />
|
|
||||||
</label>
|
|
||||||
<label class="flex w-full max-w-xs">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">是否全员参加</span>
|
|
||||||
</div>
|
|
||||||
<input type="checkbox" :checked="temporaryPrize.isAll"
|
|
||||||
@change="temporaryPrize.isAll = !temporaryPrize.isAll"
|
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
|
||||||
</label>
|
|
||||||
<label class="flex w-full max-w-xs">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">获奖人数</span>
|
|
||||||
</div>
|
|
||||||
<input type="number" v-model="temporaryPrize.count" @change="changePersonCount" placeholder="获奖人数"
|
|
||||||
class="max-w-xs input-sm input input-bordered" />
|
|
||||||
</label>
|
|
||||||
<label class="flex w-full max-w-xs">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">已获奖人数</span>
|
|
||||||
</div>
|
|
||||||
<input disabled type="number" v-model="temporaryPrize.isUsedCount" placeholder="获奖人数"
|
|
||||||
class="max-w-xs input-sm input input-bordered" />
|
|
||||||
</label>
|
|
||||||
<label class="flex w-full max-w-xs" v-if="temporaryPrize.separateCount">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">单次抽取个数</span>
|
|
||||||
</div>
|
|
||||||
<div class="flex justify-start h-full" @click="selectPrize(temporaryPrize)">
|
|
||||||
<ul class="flex flex-wrap w-full h-full gap-1 p-0 pt-1 m-0 cursor-pointer"
|
|
||||||
v-if="temporaryPrize.separateCount.countList.length">
|
|
||||||
<li class="relative flex items-center justify-center w-8 h-8 bg-slate-600/60 separated"
|
|
||||||
v-for="se in temporaryPrize.separateCount.countList" :key="se.id">
|
|
||||||
<div class="flex items-center justify-center w-full h-full tooltip"
|
|
||||||
:data-tip="'已抽取:' + se.isUsedCount + '/' + se.count">
|
|
||||||
<div class="absolute left-0 z-50 h-full bg-blue-300/80"
|
|
||||||
:style="`width:${se.isUsedCount * 100 / se.count}%`"></div>
|
|
||||||
<span>{{ se.count }}</span>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button v-else class="btn btn-secondary btn-xs">设置</button>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<label class="flex w-full max-w-xs">
|
|
||||||
<div class="label">
|
|
||||||
<span class="label-text">图片</span>
|
|
||||||
</div>
|
|
||||||
<select class="flex-1 w-12 select select-warning select-sm" v-model="temporaryPrize.picture">
|
|
||||||
<option v-if="temporaryPrize.picture.id" :value="{ id: '', name: '', url: '' }">❌
|
|
||||||
</option>
|
|
||||||
<option disabled selected>选择一张图片</option>
|
|
||||||
<option class="w-auto" v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{
|
|
||||||
picItem.name }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="modal-action">
|
|
||||||
<form method="dialog" class="flex gap-3">
|
|
||||||
<button class="btn btn-sm" @click="submitTemporaryPrize">确定</button>
|
|
||||||
<button class="btn btn-sm">取消</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</dialog>
|
<input
|
||||||
<EditSeparateDialog :totalNumber="selectedPrize?.count" :separated-number="selectedPrize?.separateCount.countList"
|
v-model="temporaryPrize.name" type="text" :placeholder="t('placeHolder.name')"
|
||||||
@submitData="submitData" />
|
class="max-w-xs input-sm input input-bordered"
|
||||||
<div ref="prizeListContainerRef">
|
>
|
||||||
<div class="h-20 w-72" :class="temporaryPrize.isShow ? 'current-prize' : ''" v-if="temporaryPrize.isShow">
|
</label>
|
||||||
<div class="relative flex flex-row items-center justify-between w-full h-full shadow-xl card bg-base-100">
|
<label class="flex w-full max-w-xs">
|
||||||
<div v-if="temporaryPrize.isUsed"
|
<div class="label">
|
||||||
class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"></div>
|
<span class="label-text">{{ t('table.fullParticipation') }}</span>
|
||||||
<figure class="w-10 h-10 rounded-xl">
|
|
||||||
<ImageSync v-if="temporaryPrize.picture.url" :imgItem="temporaryPrize.picture"></ImageSync>
|
|
||||||
<img v-else :src="defaultPrizeImage" alt="Prize" class="object-cover h-full rounded-xl" />
|
|
||||||
</figure>
|
|
||||||
<div class="items-center p-0 text-center card-body">
|
|
||||||
<div class="tooltip tooltip-left" :data-tip="temporaryPrize.name">
|
|
||||||
<h2 class="p-0 m-0 overflow-hidden w-28 card-title whitespace-nowrap text-ellipsis">{{
|
|
||||||
temporaryPrize.name }}</h2>
|
|
||||||
</div>
|
|
||||||
<p class="absolute z-40 p-0 m-0 text-gray-300/80 mt-9">{{ temporaryPrize.isUsedCount }}/{{
|
|
||||||
temporaryPrize.count }}</p>
|
|
||||||
<progress class="w-3/4 h-6 progress progress-primary" :value="temporaryPrize.isUsedCount"
|
|
||||||
:max="temporaryPrize.count"></progress>
|
|
||||||
<!-- <p class="p-0 m-0">{{ item.isUsedCount }}/{{ item.count }}</p> -->
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-col gap-1 mr-2">
|
|
||||||
<div class="tooltip tooltip-left" data-tip="编辑">
|
|
||||||
<div class="cursor-pointer hover:text-blue-400" @click="addTemporaryPrize">
|
|
||||||
<svg-icon name="edit"></svg-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tooltip tooltip-left" data-tip="删除">
|
|
||||||
<div class="cursor-pointer hover:text-blue-400" @click="deleteTemporaryPrize">
|
|
||||||
<svg-icon name="delete"></svg-icon>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<transition name="prize-list" :appear="true">
|
<input
|
||||||
<div v-if="prizeShow && !isMobile && !temporaryPrize.isShow" class="flex items-center">
|
type="checkbox" :checked="temporaryPrize.isAll"
|
||||||
<ul class="flex flex-col gap-1 p-2 rounded-xl bg-slate-500/50" ref="prizeListRef">
|
class="mt-2 border-solid checkbox checkbox-secondary border-1"
|
||||||
<li v-for="item in localPrizeList" :key="item.id"
|
@change="temporaryPrize.isAll = !temporaryPrize.isAll"
|
||||||
:class="currentPrize.id == item.id ? 'current-prize' : ''">
|
>
|
||||||
<div class="relative flex flex-row items-center justify-between w-64 h-20 shadow-xl card bg-base-100"
|
</label>
|
||||||
v-if="item.isShow">
|
<label class="flex w-full max-w-xs">
|
||||||
<div v-if="item.isUsed"
|
<div class="label">
|
||||||
class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"></div>
|
<span class="label-text">{{ t('table.setLuckyNumber') }}</span>
|
||||||
<figure class="w-10 h-10 rounded-xl">
|
</div>
|
||||||
<ImageSync v-if="item.picture.url" :imgItem="item.picture"></ImageSync>
|
<input
|
||||||
<img v-else :src="defaultPrizeImage" alt="Prize"
|
v-model="temporaryPrize.count" type="number" :placeholder="t('placeHolder.winnerCount')" class="max-w-xs input-sm input input-bordered"
|
||||||
class="object-cover h-full rounded-xl" />
|
@change="changePersonCount"
|
||||||
</figure>
|
>
|
||||||
<div class="items-center p-0 text-center card-body">
|
</label>
|
||||||
<div class="tooltip tooltip-left" :data-tip="item.name">
|
<label class="flex w-full max-w-xs">
|
||||||
<h2
|
<div class="label">
|
||||||
class="w-24 p-0 m-0 overflow-hidden text-center card-title whitespace-nowrap text-ellipsis">
|
<span class="label-text">{{ t('table.luckyPeopleNumber') }}</span>
|
||||||
{{ item.name }}</h2>
|
</div>
|
||||||
</div>
|
<input
|
||||||
<p class="absolute z-40 p-0 m-0 text-gray-300/80 mt-9">{{ item.isUsedCount }}/{{
|
v-model="temporaryPrize.isUsedCount" disabled type="number" :placeholder="t('placeHolder.winnerCount')"
|
||||||
item.count }}</p>
|
class="max-w-xs input-sm input input-bordered"
|
||||||
<progress class="w-3/4 h-6 progress progress-primary" :value="item.isUsedCount"
|
>
|
||||||
:max="item.count"></progress>
|
</label>
|
||||||
<!-- <p class="p-0 m-0">{{ item.isUsedCount }}/{{ item.count }}</p> -->
|
<label v-if="temporaryPrize.separateCount" class="flex w-full max-w-xs">
|
||||||
</div>
|
<div class="label">
|
||||||
</div>
|
<span class="label-text">{{ t('table.onceNumber') }}</span>
|
||||||
</li>
|
</div>
|
||||||
</ul>
|
<div class="flex justify-start h-full" @click="selectPrize(temporaryPrize)">
|
||||||
<div class="flex flex-col gap-3">
|
<ul
|
||||||
<div class="tooltip tooltip-right" data-tip="奖项列表">
|
v-if="temporaryPrize.separateCount.countList.length"
|
||||||
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
class="flex flex-wrap w-full h-full gap-1 p-0 pt-1 m-0 cursor-pointer"
|
||||||
@click="prizeShow = !prizeShow">
|
>
|
||||||
<svg-icon name="arrow_left" class="w-full h-full"></svg-icon>
|
<li
|
||||||
</div>
|
v-for="se in temporaryPrize.separateCount.countList"
|
||||||
</div>
|
:key="se.id" class="relative flex items-center justify-center w-8 h-8 bg-slate-600/60 separated"
|
||||||
<div class="tooltip tooltip-right" data-tip="添加抽奖">
|
>
|
||||||
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
<div
|
||||||
@click="addTemporaryPrize">
|
class="flex items-center justify-center w-full h-full tooltip"
|
||||||
<svg-icon name="add" class="w-full h-full"></svg-icon>
|
:data-tip="`${t('tooltip.doneCount') + se.isUsedCount}/${se.count}`"
|
||||||
</div>
|
>
|
||||||
</div>
|
<div
|
||||||
</div>
|
class="absolute left-0 z-50 h-full bg-blue-300/80"
|
||||||
</div>
|
:style="`width:${se.isUsedCount * 100 / se.count}%`"
|
||||||
</transition>
|
/>
|
||||||
|
<span>{{ se.count }}</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<button v-else class="btn btn-secondary btn-xs">{{ t('button.setting') }}</button>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<label class="flex w-full max-w-xs">
|
||||||
|
<div class="label">
|
||||||
|
<span class="label-text">{{ t('table.image') }}</span>
|
||||||
|
</div>
|
||||||
|
<select v-model="temporaryPrize.picture" class="flex-1 w-12 select select-warning select-sm">
|
||||||
|
<option v-if="temporaryPrize.picture.id" :value="{ id: '', name: '', url: '' }">❌
|
||||||
|
</option>
|
||||||
|
<option disabled selected>{{ t('table.selectPicture') }}</option>
|
||||||
|
<option v-for="picItem in localImageList" :key="picItem.id" class="w-auto" :value="picItem">{{
|
||||||
|
picItem.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="modal-action">
|
||||||
<transition name="prize-operate" :appear="true">
|
<form method="dialog" class="flex gap-3">
|
||||||
<div class="tooltip tooltip-right" data-tip="奖项列表" v-show="!prizeShow">
|
<button class="btn btn-sm" @click="submitTemporaryPrize">
|
||||||
<div class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
{{ t('button.confirm') }}
|
||||||
@click="prizeShow = !prizeShow">
|
</button>
|
||||||
<svg-icon name="arrow_right" class="w-full h-full"></svg-icon>
|
<button class="btn btn-sm">
|
||||||
</div>
|
{{ t('button.cancel') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<EditSeparateDialog
|
||||||
|
:total-number="selectedPrize?.count" :separated-number="selectedPrize?.separateCount.countList"
|
||||||
|
@submit-data="submitData"
|
||||||
|
/>
|
||||||
|
<div ref="prizeListContainerRef">
|
||||||
|
<div v-if="temporaryPrize.isShow" class="h-20 w-72" :class="temporaryPrize.isShow ? 'current-prize' : ''">
|
||||||
|
<div class="relative flex flex-row items-center justify-between w-full h-full shadow-xl card bg-base-100">
|
||||||
|
<div
|
||||||
|
v-if="temporaryPrize.isUsed"
|
||||||
|
class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"
|
||||||
|
/>
|
||||||
|
<figure class="w-10 h-10 rounded-xl">
|
||||||
|
<ImageSync v-if="temporaryPrize.picture.url" :img-item="temporaryPrize.picture" />
|
||||||
|
<img v-else :src="defaultPrizeImage" alt="Prize" class="object-cover h-full rounded-xl">
|
||||||
|
</figure>
|
||||||
|
<div class="items-center p-0 text-center card-body">
|
||||||
|
<div class="tooltip tooltip-left" :data-tip="temporaryPrize.name">
|
||||||
|
<h2 class="p-0 m-0 overflow-hidden w-28 card-title whitespace-nowrap text-ellipsis">
|
||||||
|
{{
|
||||||
|
temporaryPrize.name }}
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
</transition>
|
<p class="absolute z-40 p-0 m-0 text-gray-300/80 mt-9">
|
||||||
|
{{ temporaryPrize.isUsedCount }}/{{
|
||||||
|
temporaryPrize.count }}
|
||||||
|
</p>
|
||||||
|
<progress
|
||||||
|
class="w-3/4 h-6 progress progress-primary" :value="temporaryPrize.isUsedCount"
|
||||||
|
:max="temporaryPrize.count"
|
||||||
|
/>
|
||||||
|
<!-- <p class="p-0 m-0">{{ item.isUsedCount }}/{{ item.count }}</p> -->
|
||||||
|
</div>
|
||||||
|
<div class="flex flex-col gap-1 mr-2">
|
||||||
|
<div class="tooltip tooltip-left" :data-tip="t('tooltip.edit')">
|
||||||
|
<div class="cursor-pointer hover:text-blue-400" @click="addTemporaryPrize">
|
||||||
|
<svg-icon name="edit" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-left" :data-tip="t('tooltip.delete')">
|
||||||
|
<div class="cursor-pointer hover:text-blue-400" @click="deleteTemporaryPrize">
|
||||||
|
<svg-icon name="delete" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<transition name="prize-list" :appear="true">
|
||||||
|
<div v-if="prizeShow && !isMobile && !temporaryPrize.isShow" class="flex items-center">
|
||||||
|
<ul ref="prizeListRef" class="flex flex-col gap-1 p-2 rounded-xl bg-slate-500/50">
|
||||||
|
<li
|
||||||
|
v-for="item in localPrizeList" :key="item.id"
|
||||||
|
:class="currentPrize.id === item.id ? 'current-prize' : ''"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="item.isShow"
|
||||||
|
class="relative flex flex-row items-center justify-between w-64 h-20 shadow-xl card bg-base-100"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="item.isUsed"
|
||||||
|
class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"
|
||||||
|
/>
|
||||||
|
<figure class="w-10 h-10 rounded-xl">
|
||||||
|
<ImageSync v-if="item.picture.url" :img-item="item.picture" />
|
||||||
|
<img
|
||||||
|
v-else :src="defaultPrizeImage" alt="Prize"
|
||||||
|
class="object-cover h-full rounded-xl"
|
||||||
|
>
|
||||||
|
</figure>
|
||||||
|
<div class="items-center p-0 text-center card-body">
|
||||||
|
<div class="tooltip tooltip-left" :data-tip="item.name">
|
||||||
|
<h2
|
||||||
|
class="w-24 p-0 m-0 overflow-hidden text-center card-title whitespace-nowrap text-ellipsis"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
<p class="absolute z-40 p-0 m-0 text-gray-300/80 mt-9">
|
||||||
|
{{ item.isUsedCount }}/{{
|
||||||
|
item.count }}
|
||||||
|
</p>
|
||||||
|
<progress
|
||||||
|
class="w-3/4 h-6 progress progress-primary" :value="item.isUsedCount"
|
||||||
|
:max="item.count"
|
||||||
|
/>
|
||||||
|
<!-- <p class="p-0 m-0">{{ item.isUsedCount }}/{{ item.count }}</p> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="flex flex-col gap-3">
|
||||||
|
<div class="tooltip tooltip-right" :data-tip="t('tooltip.prizeList')">
|
||||||
|
<div
|
||||||
|
class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
||||||
|
@click="prizeShow = !prizeShow"
|
||||||
|
>
|
||||||
|
<svg-icon name="arrow_left" class="w-full h-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tooltip tooltip-right" :data-tip="t('tooltip.addActivity')">
|
||||||
|
<div
|
||||||
|
class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
||||||
|
@click="addTemporaryPrize"
|
||||||
|
>
|
||||||
|
<svg-icon name="add" class="w-full h-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<transition name="prize-operate" :appear="true">
|
||||||
|
<div v-show="!prizeShow" class="tooltip tooltip-right" :data-tip="t('tooltip.prizeList')">
|
||||||
|
<div
|
||||||
|
class="flex items-center w-6 h-8 rounded-r-lg cursor-pointer prize-option bg-slate-500/50"
|
||||||
|
@click="prizeShow = !prizeShow"
|
||||||
|
>
|
||||||
|
<svg-icon name="arrow_right" class="w-full h-full" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
@@ -311,7 +366,6 @@ onMounted(() => {
|
|||||||
translate: 0% 0%;
|
translate: 0% 0%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.current-prize::after {
|
.current-prize::after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -401,4 +455,5 @@ onMounted(() => {
|
|||||||
100% {
|
100% {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
}</style>
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
7
src/vite-env.d.ts
vendored
7
src/vite-env.d.ts
vendored
@@ -1,9 +1,10 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
declare module '*.vue' {
|
declare module '*.vue' {
|
||||||
import type { DefineComponent } from 'vue';
|
import type { DefineComponent } from 'vue'
|
||||||
const component: DefineComponent<{}, {}, any>;
|
|
||||||
export default component;
|
const component: DefineComponent<object, object, any>
|
||||||
|
export default component
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'sparticles'
|
declare module 'sparticles'
|
||||||
|
|||||||
@@ -19,6 +19,6 @@
|
|||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
"include": ["src/**/*.ts","src/**/*.d.ts","src/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
|||||||
271
vite.config.ts
271
vite.config.ts
@@ -1,143 +1,150 @@
|
|||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
|
|
||||||
import { defineConfig, loadEnv } from 'vite';
|
import { createRequire } from 'node:module'
|
||||||
import vue from '@vitejs/plugin-vue';
|
import path from 'node:path'
|
||||||
import path from 'path';
|
import legacy from '@vitejs/plugin-legacy'
|
||||||
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons';
|
import vue from '@vitejs/plugin-vue'
|
||||||
import AutoImport from 'unplugin-auto-import/vite';
|
import { visualizer } from 'rollup-plugin-visualizer'
|
||||||
import Components from 'unplugin-vue-components/vite';
|
import AutoImport from 'unplugin-auto-import/vite'
|
||||||
import Icons from 'unplugin-icons/vite';
|
import IconsResolver from 'unplugin-icons/resolver'
|
||||||
import IconsResolver from 'unplugin-icons/resolver';
|
import Icons from 'unplugin-icons/vite'
|
||||||
import { visualizer } from 'rollup-plugin-visualizer';
|
import Components from 'unplugin-vue-components/vite'
|
||||||
import viteCompression from 'vite-plugin-compression';
|
import { defineConfig, loadEnv } from 'vite'
|
||||||
import legacy from '@vitejs/plugin-legacy';
|
import viteCompression from 'vite-plugin-compression'
|
||||||
// import vueDevTools from 'vite-plugin-vue-devtools'
|
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
|
||||||
|
import vueDevTools from 'vite-plugin-vue-devtools'
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
|
|
||||||
|
const require = createRequire(import.meta.url)
|
||||||
|
const process = require('node:process')
|
||||||
|
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
const env = loadEnv(mode, __dirname);
|
const env = loadEnv(mode, __dirname)
|
||||||
const chunkName = mode == 'prebuild' ? '[name]' : 'chunk';
|
const chunkName = mode === 'prebuild' ? '[name]' : 'chunk'
|
||||||
|
|
||||||
return {
|
return {
|
||||||
base:mode == 'file'?'./':'/log-lottery/',
|
base: mode === 'file' ? './' : '/log-lottery/',
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
mode == 'file'?legacy({
|
mode === 'file'
|
||||||
additionalLegacyPolyfills: ['regenerator-runtime/runtime']
|
? legacy({
|
||||||
}):null,
|
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
|
||||||
// vueDevTools(),
|
})
|
||||||
viteCompression({
|
: null,
|
||||||
verbose: true,
|
// vueDevTools(),
|
||||||
disable: false,
|
viteCompression({
|
||||||
threshold: 10240,
|
verbose: true,
|
||||||
algorithm: 'gzip',
|
disable: false,
|
||||||
ext: '.gz',
|
threshold: 10240,
|
||||||
}),
|
algorithm: 'gzip',
|
||||||
visualizer({
|
ext: '.gz',
|
||||||
emitFile: true, //是否被触摸
|
}),
|
||||||
filename: 'test.html', //生成分析网页文件名
|
visualizer({
|
||||||
open: true, //在默认用户代理中打开生成的文件
|
emitFile: true, // 是否被触摸
|
||||||
gzipSize: true, //从源代码中收集 gzip 大小并将其显示在图表中
|
filename: 'test.html', // 生成分析网页文件名
|
||||||
brotliSize: true, //从源代码中收集 brotli 大小并将其显示在图表中
|
open: true, // 在默认用户代理中打开生成的文件
|
||||||
}),
|
gzipSize: true, // 从源代码中收集 gzip 大小并将其显示在图表中
|
||||||
|
brotliSize: true, // 从源代码中收集 brotli 大小并将其显示在图表中
|
||||||
|
}),
|
||||||
|
|
||||||
createSvgIconsPlugin({
|
createSvgIconsPlugin({
|
||||||
// 指定需要缓存的图标文件夹
|
// 指定需要缓存的图标文件夹
|
||||||
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
|
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
|
||||||
// 指定symbolId格式
|
// 指定symbolId格式
|
||||||
symbolId: 'icon-[dir]-[name]',
|
symbolId: 'icon-[dir]-[name]',
|
||||||
}),
|
}),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
resolvers: [
|
resolvers: [
|
||||||
// 自动导入图标组件
|
// 自动导入图标组件
|
||||||
IconsResolver({
|
IconsResolver({
|
||||||
prefix: 'Icon',
|
prefix: 'Icon',
|
||||||
}),
|
}),
|
||||||
],
|
|
||||||
dts: path.resolve(path.resolve(__dirname, 'src'), 'auto-imports.d.ts'),
|
|
||||||
}),
|
|
||||||
Components({
|
|
||||||
resolvers: [
|
|
||||||
// 自动注册图标组件
|
|
||||||
IconsResolver({
|
|
||||||
enabledCollections: ['ep'],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
dts: path.resolve(path.resolve(__dirname, 'src'), 'components.d.ts'),
|
|
||||||
}),
|
|
||||||
Icons({
|
|
||||||
autoInstall: true,
|
|
||||||
}),
|
|
||||||
],
|
],
|
||||||
css: {
|
dts: path.resolve(path.resolve(__dirname, 'src'), 'auto-imports.d.ts'),
|
||||||
preprocessorOptions: {
|
}),
|
||||||
scss: {
|
Components({
|
||||||
additionalData: '@use "@/style/global.scss" as *;',
|
resolvers: [
|
||||||
},
|
// 自动注册图标组件
|
||||||
},
|
IconsResolver({
|
||||||
// postcss: {
|
enabledCollections: ['ep'],
|
||||||
// plugins: [
|
}),
|
||||||
// require('tailwindcss'),
|
],
|
||||||
// require('autoprefixer'),
|
dts: path.resolve(path.resolve(__dirname, 'src'), 'components.d.ts'),
|
||||||
// ]
|
}),
|
||||||
// }
|
Icons({
|
||||||
|
autoInstall: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
css: {
|
||||||
|
preprocessorOptions: {
|
||||||
|
scss: {
|
||||||
|
additionalData: '@use "@/style/global.scss" as *;',
|
||||||
},
|
},
|
||||||
server: {
|
},
|
||||||
host: 'localhost',
|
// postcss: {
|
||||||
port: 6719,
|
// plugins: [
|
||||||
proxy: {
|
// require('tailwindcss'),
|
||||||
'/api': {
|
// require('autoprefixer'),
|
||||||
target: env.VITE_BASE_URL,
|
// ]
|
||||||
// 是否跨域
|
// }
|
||||||
changeOrigin: true,
|
},
|
||||||
// 路径重写
|
server: {
|
||||||
rewrite: (path) => path.replace(/^\/api/, ''),
|
host: 'localhost',
|
||||||
},
|
port: 6719,
|
||||||
},
|
proxy: {
|
||||||
|
'/api': {
|
||||||
|
target: env.VITE_BASE_URL,
|
||||||
|
// 是否跨域
|
||||||
|
changeOrigin: true,
|
||||||
|
// 路径重写
|
||||||
|
rewrite: path => path.replace(/^\/api/, ''),
|
||||||
},
|
},
|
||||||
resolve: {
|
},
|
||||||
alias: {
|
},
|
||||||
'@': path.resolve(__dirname, './src'),
|
resolve: {
|
||||||
},
|
alias: {
|
||||||
|
'@': path.resolve(__dirname, './src'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
minify: 'terser',
|
||||||
|
terserOptions: {
|
||||||
|
compress: {
|
||||||
|
// 生产环境时移除console
|
||||||
|
drop_console: true,
|
||||||
|
drop_debugger: true,
|
||||||
},
|
},
|
||||||
build: {
|
},
|
||||||
minify: 'terser',
|
// 关闭文件计算
|
||||||
terserOptions: {
|
reportCompressedSize: false,
|
||||||
compress: {
|
// 关闭生成map文件 可以达到缩小打包体积
|
||||||
//生产环境时移除console
|
sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
|
||||||
drop_console: true,
|
rollupOptions: {
|
||||||
drop_debugger: true,
|
output: {
|
||||||
},
|
chunkFileNames: `js/${chunkName}-[hash].js`, // 引入文件名的名称
|
||||||
},
|
entryFileNames: `js/${chunkName}-[hash].js`, // 包的入口文件名称
|
||||||
// 关闭文件计算
|
assetFileNames: `[ext]/${chunkName}-[hash].[ext]`, // 资源文件像 字体,图片等
|
||||||
reportCompressedSize: false,
|
manualChunks(id: any): string {
|
||||||
// 关闭生成map文件 可以达到缩小打包体积
|
if (id.includes('node_modules')) {
|
||||||
sourcemap: false, // 这个生产环境一定要关闭,不然打包的产物会很大
|
return id
|
||||||
rollupOptions: {
|
.toString()
|
||||||
output: {
|
.split('node_modules/')[1]
|
||||||
chunkFileNames: `js/${chunkName}-[hash].js`, // 引入文件名的名称
|
.split('/')[0]
|
||||||
entryFileNames: `js/${chunkName}-[hash].js`, // 包的入口文件名称
|
.toString()
|
||||||
assetFileNames: `[ext]/${chunkName}-[hash].[ext]`, // 资源文件像 字体,图片等
|
}
|
||||||
manualChunks(id: any): string {
|
},
|
||||||
if (id.includes('node_modules')) {
|
|
||||||
return id
|
|
||||||
.toString()
|
|
||||||
.split('node_modules/')[1]
|
|
||||||
.split('/')[0]
|
|
||||||
.toString();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
// 使用这个必须在上面加/// <reference types="vitest" /> 不然会有类型报错
|
},
|
||||||
test: {
|
},
|
||||||
globals: true, // --> 0.8.1+ 请修改成globals
|
// 使用这个必须在上面加/// <reference types="vitest" /> 不然会有类型报错
|
||||||
environment: 'jsdom',
|
test: {
|
||||||
// include: ['**/__tests__/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
globals: true, // --> 0.8.1+ 请修改成globals
|
||||||
// passWithNoTests: true,
|
environment: 'jsdom',
|
||||||
transformMode: {
|
// include: ['**/__tests__/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
web: [/\.[jt]sx$/],
|
// passWithNoTests: true,
|
||||||
},
|
transformMode: {
|
||||||
},
|
web: [/\.[jt]sx$/],
|
||||||
};
|
},
|
||||||
});
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user