feat: feat
This commit is contained in:
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 [fullname]
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
118
README.md
118
README.md
@@ -1,105 +1,21 @@
|
|||||||
# Vue3 + Vite4 + Element + Windicss + Bootstrap
|
<p align="center">
|
||||||
|
<a href="http://www.form-create.com">
|
||||||
|
<svg t="1704902663531" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4318" width="200" height="200"><path d="M433.230769 630.153846m-275.692307 0a275.692308 275.692308 0 1 0 551.384615 0 275.692308 275.692308 0 1 0-551.384615 0Z" fill="#E2FFFF" p-id="4319"></path><path d="M512 0C228.903385 0 0 228.903385 0 512s228.903385 512 512 512 512-228.903385 512-512S795.096615 0 512 0z m42.968615 938.653538V883.396923c0-27.608615-21.464615-46.040615-46.040615-46.040615-24.536615 0-46.040615 21.504-46.040615 46.08v55.21723c-196.450462-21.464615-356.036923-181.090462-377.540923-377.540923H140.603077c24.536615 0 46.040615-21.504 46.040615-46.08 0-24.536615-21.504-46.001231-46.08-46.00123H85.385846c18.392615-199.522462 178.018462-362.220308 377.540923-383.684923v61.36123c0 24.576 21.504 46.08 46.08 46.08 24.536615 0 46.001231-21.504 46.001231-46.08V85.346462c202.594462 21.464615 365.292308 181.090462 383.684923 383.684923h-61.361231c-27.648 0-46.08 18.392615-46.08 46.040615 0 24.536615 21.504 46.040615 46.08 46.040615h61.361231c-21.464615 199.522462-184.162462 359.148308-383.684923 377.540923z" fill="#437DFF" p-id="4320"></path><path d="M499.396923 291.170462a19.692308 19.692308 0 0 1 25.245539 0.039384l2.520615 2.520616 9.964308 12.169846C625.427692 414.208 669.538462 495.340308 669.538462 549.218462 669.538462 637.44 599.04 708.923077 512 708.923077s-157.538462-71.483077-157.538462-159.704615c0-49.900308 37.809231-123.155692 113.506462-219.72677l18.904615-23.630769 9.964308-12.130461a19.692308 19.692308 0 0 1 2.599385-2.56z m12.603077 110.434461l-9.570462 13.075692-13.23323 18.747077-11.815385 17.644308C447.763692 496.679385 433.230769 530.313846 433.230769 549.218462c0 44.937846 35.524923 80.935385 78.769231 80.935384 43.244308 0 78.769231-35.997538 78.769231-80.935384 0-16.305231-11.027692-43.992615-33.437539-81.053539l-10.318769-16.462769a790.843077 790.843077 0 0 0-11.697231-17.565539l-13.115077-18.668307-10.200615-13.863385z" fill="#437DFF" p-id="4321"></path></svg>
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
## 文件夹介绍
|
# log-lottery
|
||||||
### 🅰️api
|
|
||||||
request.ts文件为axios封装,可在此拦截操作请求和回复
|
[](https://github.com/LOG1997/log-lottery)
|
||||||
### 🆒components
|
|
||||||
组件文件夹,存放公共组件,如SvgIcon图标组件、Table表格组件等
|
[](https://github.com/log1997)
|
||||||
### 👀hooks
|
|
||||||
封装hooks函数,公共函数的提取
|
[](https://github.com/log1997)
|
||||||
### 🪪icons
|
|
||||||
存放图标组件,图标组件使用vite插件vite-plugin-svg-icon引入
|
|
||||||
```ts
|
|
||||||
plugins[
|
|
||||||
...
|
|
||||||
createSvgIconsPlugin({
|
|
||||||
// 指定需要缓存的图标文件夹
|
|
||||||
iconDirs: [path.resolve(process.cwd(), "src/icons")],
|
|
||||||
// 指定symbolId格式
|
|
||||||
symbolId: "icon-[dir]-[name]",
|
|
||||||
}),
|
|
||||||
...
|
|
||||||
]
|
|
||||||
```
|
|
||||||
使用时在组件内按如下方法使用即可
|
|
||||||
```ts
|
|
||||||
<svg-icon :name="'menu'" class="svgMenu cursor-pointer"></svg-icon>
|
|
||||||
```
|
|
||||||
### 🏬layout
|
|
||||||
整体的的布局组件,在router文件中根路径下引入。
|
|
||||||
包含Header、Main、Footer组件,布局使用了bootstrap的响应式布局
|
|
||||||
如菜单列表的写法
|
|
||||||
```ts
|
|
||||||
<nav class="navbar navbar-expand-lg">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<button
|
|
||||||
class="navbar-toggler"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#navbarSupportedContent"
|
|
||||||
aria-controls="navbarSupportedContent"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-label="Toggle navigation"
|
|
||||||
>
|
|
||||||
<!-- <span class="navbar-toggler-icon"></span> -->
|
|
||||||
<svg-icon :name="'open'"></svg-icon>
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
class="nav-list collapse navbar-collapse"
|
|
||||||
id="navbarSupportedContent"
|
|
||||||
>
|
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
||||||
<li
|
|
||||||
class="nav-item"
|
|
||||||
v-for="item in navList.data"
|
|
||||||
:key="item.id"
|
|
||||||
@click="skip(item.url)"
|
|
||||||
>
|
|
||||||
<a class="nav-link active" aria-current="page" href="#">{{
|
|
||||||
item.name
|
|
||||||
}}</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
```
|
|
||||||
使用媒体查询监听屏幕宽度自适应调整布局
|
|
||||||
如Header组件中,屏幕宽度大于1200px时始终保持headeer栏宽度为200px
|
|
||||||
```css
|
|
||||||
// @/layout/components/Header.vue
|
|
||||||
@media screen and (min-width: 1200px) {
|
|
||||||
.header-container {
|
|
||||||
width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
其中Main组件中写入
|
|
||||||
```ts
|
|
||||||
<router-view class="main-container-content"></router-view>
|
|
||||||
```
|
|
||||||
### 🏳️⚧️router
|
|
||||||
路由管理,使用history模式
|
|
||||||
### 🛒store
|
|
||||||
状态管理,使用pinia
|
|
||||||
### 🍟style
|
|
||||||
存放样式文件,模板里主要存放的是主题文件,使用scss。
|
|
||||||
文件中的函数以及样式在main.ts中引入过后即可使用
|
|
||||||
### 🥅types
|
|
||||||
定义的类型和接口
|
|
||||||
### 🎊views
|
|
||||||
界面组件
|
|
||||||
### 🙈App.vue
|
|
||||||
界面入口
|
|
||||||
### 🧵Main.ts
|
|
||||||
项目入口文件
|
|
||||||
### 🗽env文件
|
|
||||||
根据不同环境配置的路径地址,常量名称必须是`VITE_***`格式,在vite项目中引入时的方式为`import.meta.env.VITE_***`。
|
|
||||||
还需要在`vite.config.ts`文件中设置才可引用,具体见文件
|
|
||||||
### 🪔vite.config.ts
|
|
||||||
配置了icons的引入、elemnet的按需引入和自动注册、element图标的使用、windicss的引入、符号别名的设置、server的设置。
|
|
||||||
|
|
||||||
### 📦在.env文件中修改链接
|
## License
|
||||||
|
|
||||||
|
[MIT](http://opensource.org/licenses/MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2024-present log1997
|
||||||
41
__test__/Lottery.test.ts
Normal file
41
__test__/Lottery.test.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import Button from '@/components/Button/index.vue'
|
||||||
|
|
||||||
|
import { shallowMount } from '@vue/test-utils'
|
||||||
|
import { describe, expect, test } from 'vitest'
|
||||||
|
// 测试分组
|
||||||
|
describe('Button', () => {
|
||||||
|
// mount
|
||||||
|
test('Buttons slot text', () => {
|
||||||
|
// @vue/test-utils
|
||||||
|
const wrapper = shallowMount(Button, {
|
||||||
|
slots: {
|
||||||
|
default: 'Button',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// 断言
|
||||||
|
expect(wrapper.text()).toBe('Button')
|
||||||
|
})
|
||||||
|
test('Button click', () => {
|
||||||
|
const wrapper = shallowMount(Button)
|
||||||
|
wrapper.trigger('click')
|
||||||
|
expect(wrapper.emitted('click')).toBeTruthy()
|
||||||
|
})
|
||||||
|
test('Button disabled', () => {
|
||||||
|
const wrapper = shallowMount(Button, {
|
||||||
|
props: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
wrapper.trigger('click')
|
||||||
|
expect(wrapper.emitted('click')).toBeFalsy()
|
||||||
|
})
|
||||||
|
test('Button not disabled', () => {
|
||||||
|
const wrapper = shallowMount(Button, {
|
||||||
|
props: {
|
||||||
|
disabled: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
wrapper.trigger('click')
|
||||||
|
expect(wrapper.emitted('click')).toBeTruthy()
|
||||||
|
})
|
||||||
|
})
|
||||||
20
package.json
20
package.json
@@ -1,8 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "log-lottery",
|
"name": "log-lottery",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --host 0.0.0.0",
|
"dev": "vite --host 0.0.0.0",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
@@ -13,29 +14,19 @@
|
|||||||
"lint": "eslint ./src --ext .vue,.js,.ts,.jsx,.tsx --fix"
|
"lint": "eslint ./src --ext .vue,.js,.ts,.jsx,.tsx --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.1.0",
|
"@tweenjs/tween.js": "^21.0.0",
|
||||||
"@popperjs/core": "^2.11.8",
|
|
||||||
"@radial-color-picker/vue-color-picker": "^5.0.1",
|
|
||||||
"@tsparticles/engine": "^3.0.3",
|
|
||||||
"@tsparticles/slim": "^3.0.3",
|
|
||||||
"@tsparticles/vue3": "^3.0.0",
|
|
||||||
"@vueuse/core": "^10.6.1",
|
"@vueuse/core": "^10.6.1",
|
||||||
"axios": "^1.6.1",
|
"axios": "^1.6.1",
|
||||||
"canvas-confetti": "^1.9.2",
|
"canvas-confetti": "^1.9.2",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"particles.vue3": "^2.12.0",
|
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persist": "^1.0.0",
|
"pinia-plugin-persist": "^1.0.0",
|
||||||
"sparticles": "^1.3.1",
|
"sparticles": "^1.3.1",
|
||||||
"svg-sprite-loader": "^6.0.11",
|
|
||||||
"theme-change": "^2.5.0",
|
"theme-change": "^2.5.0",
|
||||||
"three": "^0.160.0",
|
"three": "^0.160.0",
|
||||||
"three-css2drender": "^1.0.0",
|
"three-css3d": "^1.0.6",
|
||||||
"tsparticles": "^3.0.3",
|
"three-trackballcontrols": "^0.9.0",
|
||||||
"tsparticles-engine": "^2.12.0",
|
|
||||||
"vcolorpicker": "^2.0.12",
|
|
||||||
"vue": "^3.3.8",
|
"vue": "^3.3.8",
|
||||||
"vue-accessible-color-picker": "^5.0.1",
|
|
||||||
"vue-router": "^4.2.5",
|
"vue-router": "^4.2.5",
|
||||||
"vue-toast-notification": "^3",
|
"vue-toast-notification": "^3",
|
||||||
"vue3-colorpicker": "^2.2.3",
|
"vue3-colorpicker": "^2.2.3",
|
||||||
@@ -59,7 +50,6 @@
|
|||||||
"daisyui": "^4.0.4",
|
"daisyui": "^4.0.4",
|
||||||
"eslint": "^8.53.0",
|
"eslint": "^8.53.0",
|
||||||
"eslint-plugin-vue": "^9.18.1",
|
"eslint-plugin-vue": "^9.18.1",
|
||||||
"fast-glob": "^3.3.2",
|
|
||||||
"happy-dom": "^12.10.3",
|
"happy-dom": "^12.10.3",
|
||||||
"husky": "^8.0.3",
|
"husky": "^8.0.3",
|
||||||
"jsdom": "^22.1.0",
|
"jsdom": "^22.1.0",
|
||||||
|
|||||||
1005
pnpm-lock.yaml
generated
1005
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
BIN
src/assets/images/龙.png
Normal file
BIN
src/assets/images/龙.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 233 KiB |
@@ -15,8 +15,15 @@ const imgUrl=ref('')
|
|||||||
|
|
||||||
|
|
||||||
const getImageStoreItem=async (item:any):Promise<string>=>{
|
const getImageStoreItem=async (item:any):Promise<string>=>{
|
||||||
|
let image=''
|
||||||
|
if(item.url=='Storage'){
|
||||||
const key=item.id;
|
const key=item.id;
|
||||||
const image=await imageDbStore.getItem(key) as string
|
image=await imageDbStore.getItem(key) as string
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
image=item.url
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
@@ -28,7 +35,7 @@ onMounted(async ()=>{
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<img :src="imgUrl" Alt="Image"/>
|
<img :src="imgUrl" alt="Image" class="object-cover h-full rounded-xl"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang='scss' scoped>
|
<style lang='scss' scoped>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ export const useElementStyle=(element:any,cardColor:string,cardSize:{width:numbe
|
|||||||
element.children[0].style.fontSize = textSize*0.5+'px'
|
element.children[0].style.fontSize = textSize*0.5+'px'
|
||||||
|
|
||||||
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.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
|
element.children[1].style.textShadow = `0 0 12px ${rgba(cardColor, 0.95)}`
|
||||||
|
|
||||||
element.children[2].style.fontSize = textSize*0.5+'px'
|
element.children[2].style.fontSize = textSize*0.5+'px'
|
||||||
|
|||||||
1
src/icons/instagram.svg
Normal file
1
src/icons/instagram.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 256 256"><g fill="none"><rect width="256" height="256" fill="url(#skillIconsInstagram0)" rx="60"/><rect width="256" height="256" fill="url(#skillIconsInstagram1)" rx="60"/><path fill="#fff" d="M128.009 28c-27.158 0-30.567.119-41.233.604c-10.646.488-17.913 2.173-24.271 4.646c-6.578 2.554-12.157 5.971-17.715 11.531c-5.563 5.559-8.98 11.138-11.542 17.713c-2.48 6.36-4.167 13.63-4.646 24.271c-.477 10.667-.602 14.077-.602 41.236s.12 30.557.604 41.223c.49 10.646 2.175 17.913 4.646 24.271c2.556 6.578 5.973 12.157 11.533 17.715c5.557 5.563 11.136 8.988 17.709 11.542c6.363 2.473 13.631 4.158 24.275 4.646c10.667.485 14.073.604 41.23.604c27.161 0 30.559-.119 41.225-.604c10.646-.488 17.921-2.173 24.284-4.646c6.575-2.554 12.146-5.979 17.702-11.542c5.563-5.558 8.979-11.137 11.542-17.712c2.458-6.361 4.146-13.63 4.646-24.272c.479-10.666.604-14.066.604-41.225s-.125-30.567-.604-41.234c-.5-10.646-2.188-17.912-4.646-24.27c-2.563-6.578-5.979-12.157-11.542-17.716c-5.562-5.562-11.125-8.979-17.708-11.53c-6.375-2.474-13.646-4.16-24.292-4.647c-10.667-.485-14.063-.604-41.23-.604zm-8.971 18.021c2.663-.004 5.634 0 8.971 0c26.701 0 29.865.096 40.409.575c9.75.446 15.042 2.075 18.567 3.444c4.667 1.812 7.994 3.979 11.492 7.48c3.5 3.5 5.666 6.833 7.483 11.5c1.369 3.52 3 8.812 3.444 18.562c.479 10.542.583 13.708.583 40.396c0 26.688-.104 29.855-.583 40.396c-.446 9.75-2.075 15.042-3.444 18.563c-1.812 4.667-3.983 7.99-7.483 11.488c-3.5 3.5-6.823 5.666-11.492 7.479c-3.521 1.375-8.817 3-18.567 3.446c-10.542.479-13.708.583-40.409.583c-26.702 0-29.867-.104-40.408-.583c-9.75-.45-15.042-2.079-18.57-3.448c-4.666-1.813-8-3.979-11.5-7.479s-5.666-6.825-7.483-11.494c-1.369-3.521-3-8.813-3.444-18.563c-.479-10.542-.575-13.708-.575-40.413c0-26.704.096-29.854.575-40.396c.446-9.75 2.075-15.042 3.444-18.567c1.813-4.667 3.983-8 7.484-11.5c3.5-3.5 6.833-5.667 11.5-7.483c3.525-1.375 8.819-3 18.569-3.448c9.225-.417 12.8-.542 31.437-.563zm62.351 16.604c-6.625 0-12 5.37-12 11.996c0 6.625 5.375 12 12 12s12-5.375 12-12s-5.375-12-12-12zm-53.38 14.021c-28.36 0-51.354 22.994-51.354 51.355c0 28.361 22.994 51.344 51.354 51.344c28.361 0 51.347-22.983 51.347-51.344c0-28.36-22.988-51.355-51.349-51.355zm0 18.021c18.409 0 33.334 14.923 33.334 33.334c0 18.409-14.925 33.334-33.334 33.334c-18.41 0-33.333-14.925-33.333-33.334c0-18.411 14.923-33.334 33.333-33.334"/><defs><radialGradient id="skillIconsInstagram0" cx="0" cy="0" r="1" gradientTransform="matrix(0 -253.715 235.975 0 68 275.717)" gradientUnits="userSpaceOnUse"><stop stop-color="#FD5"/><stop offset=".1" stop-color="#FD5"/><stop offset=".5" stop-color="#FF543E"/><stop offset="1" stop-color="#C837AB"/></radialGradient><radialGradient id="skillIconsInstagram1" cx="0" cy="0" r="1" gradientTransform="matrix(22.25952 111.2061 -458.39518 91.75449 -42.881 18.441)" gradientUnits="userSpaceOnUse"><stop stop-color="#3771C8"/><stop offset=".128" stop-color="#3771C8"/><stop offset="1" stop-color="#60F" stop-opacity="0"/></radialGradient></defs></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
1
src/icons/twitter.svg
Normal file
1
src/icons/twitter.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="39.2" height="32" viewBox="0 0 256 209"><path fill="#55acee" d="M256 25.45a105.04 105.04 0 0 1-30.166 8.27c10.845-6.5 19.172-16.793 23.093-29.057a105.183 105.183 0 0 1-33.351 12.745C205.995 7.201 192.346.822 177.239.822c-29.006 0-52.523 23.516-52.523 52.52c0 4.117.465 8.125 1.36 11.97c-43.65-2.191-82.35-23.1-108.255-54.876c-4.52 7.757-7.11 16.78-7.11 26.404c0 18.222 9.273 34.297 23.365 43.716a52.312 52.312 0 0 1-23.79-6.57c-.003.22-.003.44-.003.661c0 25.447 18.104 46.675 42.13 51.5a52.592 52.592 0 0 1-23.718.9c6.683 20.866 26.08 36.05 49.062 36.475c-17.975 14.086-40.622 22.483-65.228 22.483c-4.24 0-8.42-.249-12.529-.734c23.243 14.902 50.85 23.597 80.51 23.597c96.607 0 149.434-80.031 149.434-149.435c0-2.278-.05-4.543-.152-6.795A106.748 106.748 0 0 0 256 25.45"/></svg>
|
||||||
|
After Width: | Height: | Size: 824 B |
@@ -28,7 +28,7 @@ export const configRoutes={
|
|||||||
name:'AllPersonConfig',
|
name:'AllPersonConfig',
|
||||||
component:()=>import('@/views/Config/Person/PersonAll.vue'),
|
component:()=>import('@/views/Config/Person/PersonAll.vue'),
|
||||||
meta:{
|
meta:{
|
||||||
title:'所有人员',
|
title:'人员名单',
|
||||||
icon:'all'
|
icon:'all'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -37,7 +37,7 @@ export const configRoutes={
|
|||||||
name:'AlreadyPerson',
|
name:'AlreadyPerson',
|
||||||
component:()=>import('@/views/Config/Person/PersonAlready.vue'),
|
component:()=>import('@/views/Config/Person/PersonAlready.vue'),
|
||||||
meta:{
|
meta:{
|
||||||
title:'已领取人员',
|
title:'中奖名单人员',
|
||||||
icon:'already'
|
icon:'already'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -84,7 +84,7 @@ export const configRoutes={
|
|||||||
name:'ImageConfig',
|
name:'ImageConfig',
|
||||||
component:()=>import('@/views/Config/Global/ImageConfig.vue'),
|
component:()=>import('@/views/Config/Global/ImageConfig.vue'),
|
||||||
meta:{
|
meta:{
|
||||||
title:'图片配置',
|
title:'图片列表',
|
||||||
icon:'image'
|
icon:'image'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -93,7 +93,7 @@ export const configRoutes={
|
|||||||
name:'MusicConfig',
|
name:'MusicConfig',
|
||||||
component:()=>import('@/views/Config/Global/MusicConfig.vue'),
|
component:()=>import('@/views/Config/Global/MusicConfig.vue'),
|
||||||
meta:{
|
meta:{
|
||||||
title:'音乐配置',
|
title:'音乐列表',
|
||||||
icon:'music'
|
icon:'music'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,25 +1,26 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { defaultMusicList,defaultImageList } from './data'
|
import { defaultMusicList,defaultImageList } from './data'
|
||||||
// import { IPrizeConfig } from '@/types/prizeConfig';
|
import {IMusic,IImage} 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: 12,
|
rowCount: 17,
|
||||||
isSHowPrizeList:true,
|
isSHowPrizeList:true,
|
||||||
topTitle:'大明内阁六部御前奏对',
|
topTitle:'大明内阁六部御前奏对',
|
||||||
theme: {
|
theme: {
|
||||||
name: 'dark',
|
name: 'dark',
|
||||||
detail: { primary: '#0f5fd3' },
|
detail: { primary: '#0f5fd3' },
|
||||||
cardColor: 'rgba(0, 255, 255)',
|
cardColor: '#ff79c6',
|
||||||
cardWidth: 140,
|
cardWidth: 140,
|
||||||
cardHeight: 200,
|
cardHeight: 200,
|
||||||
textColor: '#ffffff',
|
textColor: '#ffffff',
|
||||||
luckyCardColor:'#ECB1AC',
|
luckyCardColor:'#ECB1AC',
|
||||||
textSize: 30
|
textSize: 30
|
||||||
},
|
},
|
||||||
musicList: defaultMusicList,
|
musicList: defaultMusicList as IMusic[],
|
||||||
imageList:defaultImageList,
|
imageList:defaultImageList as IImage[],
|
||||||
},
|
},
|
||||||
currentMusic: {
|
currentMusic: {
|
||||||
item:defaultMusicList[0],
|
item:defaultMusicList[0],
|
||||||
@@ -122,7 +123,7 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
this.globalConfig.theme.textSize = textSize;
|
this.globalConfig.theme.textSize = textSize;
|
||||||
},
|
},
|
||||||
// 添加音乐
|
// 添加音乐
|
||||||
addMusic(music: any) {
|
addMusic(music: IMusic) {
|
||||||
// 验证音乐是否已存在,看name字段
|
// 验证音乐是否已存在,看name字段
|
||||||
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
for (let i = 0; i < this.globalConfig.musicList.length; i++) {
|
||||||
if (this.globalConfig.musicList[i].name === music.name) {
|
if (this.globalConfig.musicList[i].name === music.name) {
|
||||||
@@ -141,7 +142,7 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 设置当前播放音乐
|
// 设置当前播放音乐
|
||||||
setCurrentMusic(musicItem: any,paused:boolean=true) {
|
setCurrentMusic(musicItem: IMusic,paused:boolean=true) {
|
||||||
this.currentMusic={
|
this.currentMusic={
|
||||||
item:musicItem,
|
item:musicItem,
|
||||||
paused:paused,
|
paused:paused,
|
||||||
@@ -149,14 +150,14 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
},
|
},
|
||||||
// 重置音乐列表
|
// 重置音乐列表
|
||||||
resetMusicList() {
|
resetMusicList() {
|
||||||
this.globalConfig.musicList = defaultMusicList;
|
this.globalConfig.musicList = defaultMusicList as IMusic[];
|
||||||
},
|
},
|
||||||
// 清空音乐列表
|
// 清空音乐列表
|
||||||
clearMusicList() {
|
clearMusicList() {
|
||||||
this.globalConfig.musicList = [];
|
this.globalConfig.musicList = [] as IMusic[];
|
||||||
},
|
},
|
||||||
// 添加图片
|
// 添加图片
|
||||||
addImage(image:any){
|
addImage(image:IImage){
|
||||||
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
|
for (let i = 0; i < this.globalConfig.imageList.length; i++) {
|
||||||
if (this.globalConfig.imageList[i].name === image.name) {
|
if (this.globalConfig.imageList[i].name === image.name) {
|
||||||
return;
|
return;
|
||||||
@@ -175,11 +176,11 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
},
|
},
|
||||||
// 重置图片列表
|
// 重置图片列表
|
||||||
resetImageList() {
|
resetImageList() {
|
||||||
this.globalConfig.imageList = defaultImageList;
|
this.globalConfig.imageList = defaultImageList as IImage[];
|
||||||
},
|
},
|
||||||
// 清空图片列表
|
// 清空图片列表
|
||||||
clearImageList() {
|
clearImageList() {
|
||||||
this.globalConfig.imageList = [];
|
this.globalConfig.imageList = [] as IImage[]
|
||||||
},
|
},
|
||||||
// 设置是否显示奖品列表
|
// 设置是否显示奖品列表
|
||||||
setIsShowPrizeList(isShowPrizeList: boolean) {
|
setIsShowPrizeList(isShowPrizeList: boolean) {
|
||||||
@@ -202,11 +203,11 @@ export const useGlobalConfig = defineStore('global', {
|
|||||||
textSize: 30
|
textSize: 30
|
||||||
|
|
||||||
},
|
},
|
||||||
musicList: defaultMusicList,
|
musicList: defaultMusicList as IMusic[],
|
||||||
imageList:defaultImageList,
|
imageList:defaultImageList as IImage[],
|
||||||
},
|
},
|
||||||
this.currentMusic= {
|
this.currentMusic= {
|
||||||
item:defaultMusicList[0],
|
item:defaultMusicList[0] as IMusic,
|
||||||
paused:true,
|
paused:true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { IPersonConfig } from '@/types/personConfig';
|
import { IPersonConfig } from '@/types/storeType';
|
||||||
import { IPrizeConfig } from '@/types/prizeConfig';
|
import { IPrizeConfig } from '@/types/storeType';
|
||||||
import { defaultPersonList } from './data'
|
import { defaultPersonList } from './data'
|
||||||
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[],
|
||||||
// notPersonList: [] as IPersonConfig[],
|
|
||||||
tableRowCount: 12,
|
|
||||||
showField: [] as any[]
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -29,20 +26,16 @@ export const usePersonConfig = defineStore('person', {
|
|||||||
return item.isWin === true;
|
return item.isWin === true;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
// 获取中奖人员详情
|
||||||
|
getAlreadyPersonDetail(state) {
|
||||||
|
return state.personConfig.alreadyPersonList
|
||||||
|
},
|
||||||
// 获取未中奖人员名单
|
// 获取未中奖人员名单
|
||||||
getNotPersonList(state) {
|
getNotPersonList(state) {
|
||||||
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
return state.personConfig.allPersonList.filter((item: IPersonConfig) => {
|
||||||
return item.isWin === false;
|
return item.isWin === false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 获取table列数
|
|
||||||
getTableRowCount(state) {
|
|
||||||
return state.personConfig.tableRowCount;
|
|
||||||
},
|
|
||||||
// 获取要展示那些字段
|
|
||||||
getShowField(state) {
|
|
||||||
return state.personConfig.showField;
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
// 添加未中奖人员
|
// 添加未中奖人员
|
||||||
@@ -63,15 +56,23 @@ export const usePersonConfig = defineStore('person', {
|
|||||||
this.personConfig.allPersonList.map((item: IPersonConfig) => {
|
this.personConfig.allPersonList.map((item: IPersonConfig) => {
|
||||||
if (item.id === person.id && prize != null) {
|
if (item.id === person.id && prize != null) {
|
||||||
item.isWin = true
|
item.isWin = true
|
||||||
item.prizeName = prize.name
|
// person.isWin = true
|
||||||
|
item.prizeName += prize.name
|
||||||
|
// person.prizeName += prize.name
|
||||||
item.prizeTime = new Date().toString()
|
item.prizeTime = new Date().toString()
|
||||||
|
// person.prizeTime = new Date().toString()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
console.log('person;;',person)
|
||||||
|
this.personConfig.alreadyPersonList.push(person);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
// 从已中奖移动到未中奖
|
// 从已中奖移动到未中奖
|
||||||
moveAlreadyToNot(person: IPersonConfig) {
|
moveAlreadyToNot(person: IPersonConfig) {
|
||||||
if (person.id != undefined || person.id != null) {
|
if (person.id == undefined || person.id == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const alreadyPersonListLength= this.personConfig.alreadyPersonList.length
|
||||||
for (let i = 0; i < this.personConfig.allPersonList.length; i++) {
|
for (let i = 0; i < this.personConfig.allPersonList.length; i++) {
|
||||||
if (person.id === this.personConfig.allPersonList[i].id) {
|
if (person.id === this.personConfig.allPersonList[i].id) {
|
||||||
this.personConfig.allPersonList[i].isWin = false
|
this.personConfig.allPersonList[i].isWin = false
|
||||||
@@ -81,39 +82,49 @@ export const usePersonConfig = defineStore('person', {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(let i=0;i<alreadyPersonListLength;i++){
|
||||||
|
this.personConfig.alreadyPersonList=this.personConfig.alreadyPersonList.filter((item:IPersonConfig)=>{
|
||||||
|
return item.id!==person.id
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// 删除指定人员
|
// 删除指定人员
|
||||||
deletePerson(person: IPersonConfig) {
|
deletePerson(person: IPersonConfig) {
|
||||||
if (person.id != undefined || person.id != null) {
|
if (person.id != undefined || person.id != null) {
|
||||||
this.personConfig.allPersonList = this.personConfig.allPersonList.filter((item: IPersonConfig) => item.id !== person.id);
|
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() {
|
deleteAllPerson() {
|
||||||
this.personConfig.allPersonList = [];
|
this.personConfig.allPersonList = [];
|
||||||
|
this.personConfig.alreadyPersonList = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
// 重置所有人员
|
// 删除所有人员
|
||||||
resetPerson() {
|
resetPerson() {
|
||||||
this.personConfig.allPersonList = [];
|
this.personConfig.allPersonList = [];
|
||||||
|
this.personConfig.alreadyPersonList = [];
|
||||||
},
|
},
|
||||||
// 重置已中奖人员
|
// 重置已中奖人员
|
||||||
resetAlreadyPerson() {
|
resetAlreadyPerson() {
|
||||||
// 把已中奖人员合并到未中奖人员,要验证是否已存在
|
// 把已中奖人员合并到未中奖人员,要验证是否已存在
|
||||||
this.personConfig.allPersonList.forEach((item: IPersonConfig) => {
|
this.personConfig.allPersonList.forEach((item: IPersonConfig) => {
|
||||||
item.isWin = false;
|
item.isWin = false;
|
||||||
|
item.prizeName = '';
|
||||||
|
item.prizeTime = '';
|
||||||
});
|
});
|
||||||
|
this.personConfig.alreadyPersonList=[];
|
||||||
},
|
},
|
||||||
setDefaultPersonList() {
|
setDefaultPersonList() {
|
||||||
this.personConfig.allPersonList = defaultPersonList;
|
this.personConfig.allPersonList = defaultPersonList;
|
||||||
|
this.personConfig.alreadyPersonList=[];
|
||||||
},
|
},
|
||||||
// 重置所有配置
|
// 重置所有配置
|
||||||
reset() {
|
reset() {
|
||||||
this.personConfig = {
|
this.personConfig = {
|
||||||
allPersonList: [] as IPersonConfig[],
|
allPersonList: [] as IPersonConfig[],
|
||||||
tableRowCount: 12,
|
alreadyPersonList: [] as IPersonConfig[],
|
||||||
showField: [] as string[]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { IPrizeConfig } from '@/types/prizeConfig';
|
import { IPrizeConfig } from '@/types/storeType';
|
||||||
import { defaultPrizeList } from './data';
|
import { defaultPrizeList } from './data';
|
||||||
export const usePrizeConfig = defineStore('prize', {
|
export const usePrizeConfig = defineStore('prize', {
|
||||||
state() {
|
state() {
|
||||||
@@ -71,11 +71,11 @@ return state.prizeConfig.prizeList;
|
|||||||
},
|
},
|
||||||
// 删除全部奖项
|
// 删除全部奖项
|
||||||
deleteAllPrizeConfig() {
|
deleteAllPrizeConfig() {
|
||||||
this.prizeConfig.prizeList = [];
|
this.prizeConfig.prizeList = [] as IPrizeConfig[];
|
||||||
},
|
},
|
||||||
// 设置当前奖项
|
// 设置当前奖项
|
||||||
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
setCurrentPrize(prizeConfigItem: IPrizeConfig) {
|
||||||
this.prizeConfig.currentPrize = prizeConfigItem;
|
this.prizeConfig.currentPrize = prizeConfigItem
|
||||||
},
|
},
|
||||||
// 重置所有配置
|
// 重置所有配置
|
||||||
resetDefault() {
|
resetDefault() {
|
||||||
@@ -97,7 +97,7 @@ return state.prizeConfig.prizeList;
|
|||||||
isShow: true,
|
isShow: true,
|
||||||
isUsed: false,
|
isUsed: false,
|
||||||
frequency: 1,
|
frequency: 1,
|
||||||
},
|
} as IPrizeConfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
export interface IPersonConfig {
|
|
||||||
id: number;
|
|
||||||
uid: string;
|
|
||||||
name: string;
|
|
||||||
department:string;
|
|
||||||
isWin:boolean;
|
|
||||||
x:number;
|
|
||||||
y:number
|
|
||||||
createTime: string;
|
|
||||||
updateTime: string;
|
|
||||||
prizeName: string;
|
|
||||||
prizeTime: string;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
export interface IPrizeConfig {
|
|
||||||
id: number|string;
|
|
||||||
name:string;
|
|
||||||
sort:number;
|
|
||||||
isAll:boolean;
|
|
||||||
count:number;
|
|
||||||
isUsedCount:number,
|
|
||||||
picture:{
|
|
||||||
id:string|number,
|
|
||||||
name:string,
|
|
||||||
url:string
|
|
||||||
};
|
|
||||||
desc:string;
|
|
||||||
isShow:boolean;
|
|
||||||
isUsed:boolean,
|
|
||||||
frequency:number;
|
|
||||||
}
|
|
||||||
41
src/types/storeType.ts
Normal file
41
src/types/storeType.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
export interface IPersonConfig {
|
||||||
|
id: number;
|
||||||
|
uid: string;
|
||||||
|
name: string;
|
||||||
|
department:string;
|
||||||
|
isWin:boolean;
|
||||||
|
x:number;
|
||||||
|
y:number
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
prizeName: string;
|
||||||
|
prizeTime: string;
|
||||||
|
}
|
||||||
|
export interface IPrizeConfig {
|
||||||
|
id: number|string;
|
||||||
|
name:string;
|
||||||
|
sort:number;
|
||||||
|
isAll:boolean;
|
||||||
|
count:number;
|
||||||
|
isUsedCount:number,
|
||||||
|
picture:{
|
||||||
|
id:string|number,
|
||||||
|
name:string,
|
||||||
|
url:string
|
||||||
|
};
|
||||||
|
desc:string;
|
||||||
|
isShow:boolean;
|
||||||
|
isUsed:boolean,
|
||||||
|
frequency:number;
|
||||||
|
}
|
||||||
|
export interface IMusic{
|
||||||
|
id:string,
|
||||||
|
name:string,
|
||||||
|
url:string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IImage{
|
||||||
|
id:string,
|
||||||
|
name:string,
|
||||||
|
url:string,
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
export interface TableItemType {
|
|
||||||
prop: string;
|
|
||||||
label: string;
|
|
||||||
width: number;
|
|
||||||
image?: boolean;
|
|
||||||
actions?: actionsItemType[];
|
|
||||||
aligen?: string;
|
|
||||||
formatter?: ItemFuncType;
|
|
||||||
getType?: ItemFuncType;
|
|
||||||
}
|
|
||||||
interface ItemFuncType {
|
|
||||||
(row: any): any;
|
|
||||||
}
|
|
||||||
interface actionsItemType {
|
|
||||||
name: string;
|
|
||||||
func: any;
|
|
||||||
type?: any;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// 用户的类型声明文件
|
|
||||||
export interface IUser {
|
|
||||||
name: string;
|
|
||||||
age: number;
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
export const readFile = (file: any): Promise<any> => {
|
export const 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)
|
||||||
@@ -8,7 +8,7 @@ export const readFile = (file: any): Promise<any> => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const readImage = (file: any): Promise<any> => {
|
export const 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)
|
||||||
@@ -17,15 +17,3 @@ export const readImage = (file: any): Promise<any> => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export const readMusic = (file: any): Promise<any> => {
|
|
||||||
return new Promise(resolve => {
|
|
||||||
const reader = new FileReader()
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
reader.onload = (ev: any) => {
|
|
||||||
resolve({dataUrl:ev.target.result,fileName:file.name})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ watch(() => formData.value.rowCount, () => {
|
|||||||
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(themeValue, (val: any) => {
|
||||||
const selectedThemeDetail = daisyuiThemeList.value[val]
|
const selectedThemeDetail = daisyuiThemeList.value[val]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted, watch } from 'vue'
|
||||||
import { readImage } from '@/utils/file'
|
import { IImage } from '@/types/storeType'
|
||||||
|
import { readFileData } from '@/utils/file'
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
@@ -14,14 +15,14 @@ const imgUploadToast = ref(0) //0是不显示,1是成功,2是失败,3是不
|
|||||||
const imageDbStore = localforage.createInstance({
|
const imageDbStore = localforage.createInstance({
|
||||||
name: 'imgStore'
|
name: 'imgStore'
|
||||||
})
|
})
|
||||||
const handleFileChange = async (e: any) => {
|
const handleFileChange = async (e: Event) => {
|
||||||
const isImage= /image*/.test(e.target.files[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 readImage(e.target.files[0])
|
let { 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
|
||||||
@@ -45,7 +46,7 @@ const getImageDbStore =async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const removeImage=(item:any)=>{
|
const 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)
|
||||||
@@ -91,8 +92,8 @@ watch(() => imgUploadToast.value, (val) => {
|
|||||||
<div class="flex items-center gap-8">
|
<div class="flex items-center gap-8">
|
||||||
<div class="avatar h-14">
|
<div class="avatar h-14">
|
||||||
<div class="w-12 h-12 mask mask-squircle hover:w-14 hover: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" />
|
<!-- <img v-if="item.url!=='Storage'" :src="item.url" alt="Avatar Tailwind CSS Component" /> -->
|
||||||
<ImageSync v-else :imgItem="item"></ImageSync>
|
<ImageSync :imgItem="item"></ImageSync>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-64">
|
<div class="w-64">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import {storeToRefs } from 'pinia'
|
import {storeToRefs } from 'pinia'
|
||||||
import { readMusic } from '@/utils/file'
|
import { IMusic } from '@/types/storeType';
|
||||||
|
import { readFileData } from '@/utils/file'
|
||||||
import useStore from '@/store';
|
import useStore from '@/store';
|
||||||
|
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
@@ -15,11 +16,11 @@ 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: any) => {
|
const play = async (item: IMusic) => {
|
||||||
globalConfig.setCurrentMusic(item,false)
|
globalConfig.setCurrentMusic(item,false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const deleteMusic = (item: any) => {
|
const deleteMusic = (item: IMusic) => {
|
||||||
globalConfig.removeMusic(item.id)
|
globalConfig.removeMusic(item.id)
|
||||||
audioDbStore.removeItem(item.name)
|
audioDbStore.removeItem(item.name)
|
||||||
// setTimeout(()=>{
|
// setTimeout(()=>{
|
||||||
@@ -46,14 +47,14 @@ const getMusicDbStore = async () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const handleFileChange = async (e: any) => {
|
const handleFileChange = async (e: Event) => {
|
||||||
const isAudio = /audio*/.test(e.target.files[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 readMusic(e.target.files[0])
|
let { 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
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted } from 'vue';
|
import { ref, onMounted } from 'vue';
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
|
import { IPersonConfig } from '@/types/storeType';
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import * as XLSX from 'xlsx'
|
import * as XLSX from 'xlsx'
|
||||||
import { readFile } from '@/utils/file'
|
import { readFileBinary } from '@/utils/file'
|
||||||
import { filterData, addOtherInfo } from '@/utils'
|
import { filterData, addOtherInfo } from '@/utils'
|
||||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||||
|
|
||||||
@@ -16,9 +17,11 @@ const limitType = '.xlsx,.xls'
|
|||||||
const excelData = ref<any[]>([])
|
const excelData = ref<any[]>([])
|
||||||
// const personList = ref<any[]>([])
|
// const personList = ref<any[]>([])
|
||||||
|
|
||||||
|
const resetDataDialog=ref()
|
||||||
|
const delAllDataDialog=ref()
|
||||||
|
|
||||||
const handleFileChange = async (e: any) => {
|
const handleFileChange = async (e: Event) => {
|
||||||
let dataBinary = await readFile(e.target.files[0])
|
let dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
|
||||||
let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
|
let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
|
||||||
let workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
let workSheet = workBook.Sheets[workBook.SheetNames[0]]
|
||||||
excelData.value = XLSX.utils.sheet_to_json(workSheet)
|
excelData.value = XLSX.utils.sheet_to_json(workSheet)
|
||||||
@@ -27,12 +30,51 @@ const handleFileChange = async (e: any) => {
|
|||||||
personConfig.resetPerson()
|
personConfig.resetPerson()
|
||||||
personConfig.addNotPersonList(allData)
|
personConfig.addNotPersonList(allData)
|
||||||
}
|
}
|
||||||
|
const exportData = () => {
|
||||||
|
let data = JSON.parse(JSON.stringify(allPersonList.value))
|
||||||
|
// 排除一些字段
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
|
delete data[i].x
|
||||||
|
delete data[i].y
|
||||||
|
delete data[i].id
|
||||||
|
delete data[i].createTime
|
||||||
|
delete data[i].updateTime
|
||||||
|
// 修改字段名称
|
||||||
|
if (data[i].isWin) {
|
||||||
|
data[i].isWin = '是'
|
||||||
|
} else {
|
||||||
|
data[i].isWin = '否'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let dataString = JSON.stringify(data)
|
||||||
|
dataString = dataString
|
||||||
|
.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')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetData = () => {
|
||||||
|
personConfig.resetAlreadyPerson()
|
||||||
|
}
|
||||||
|
|
||||||
const deleteAll = () => {
|
const deleteAll = () => {
|
||||||
personConfig.deleteAllPerson()
|
personConfig.deleteAllPerson()
|
||||||
}
|
}
|
||||||
|
|
||||||
const delPersonItem = (row: any) => {
|
const delPersonItem = (row: IPersonConfig) => {
|
||||||
personConfig.deletePerson(row)
|
personConfig.deletePerson(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +98,7 @@ const tableColumns = [
|
|||||||
{
|
{
|
||||||
label: '是否已中奖',
|
label: '是否已中奖',
|
||||||
props: 'isWin',
|
props: 'isWin',
|
||||||
formatValue(row: any) {
|
formatValue(row: IPersonConfig) {
|
||||||
return row.isWin ? '是' : '否'
|
return row.isWin ? '是' : '否'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -73,7 +115,7 @@ const tableColumns = [
|
|||||||
{
|
{
|
||||||
label: '删除',
|
label: '删除',
|
||||||
type: 'btn-error',
|
type: 'btn-error',
|
||||||
onClick: (row: any) => {
|
onClick: (row: IPersonConfig) => {
|
||||||
delPersonItem(row)
|
delPersonItem(row)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -86,11 +128,38 @@ onMounted(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<dialog id="my_modal_1" ref="resetDataDialog" class="border-none modal">
|
||||||
|
<div class="modal-box">
|
||||||
|
<h3 class="text-lg font-bold">提示!</h3>
|
||||||
|
<p class="py-4">该操作会重置所有人员数据,是否继续?</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="resetDataDialog.close()">取消</button>
|
||||||
|
<button class="btn" @click="resetData">确定</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<dialog id="my_modal_1" ref="delAllDataDialog" class="border-none modal">
|
||||||
|
<div class="modal-box">
|
||||||
|
<h3 class="text-lg font-bold">提示!</h3>
|
||||||
|
<p class="py-4">该操作会删除所有人员数据,是否继续?</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()">取消</button>
|
||||||
|
<button class="btn" @click="deleteAll">确定</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
<div class="min-w-1000px">
|
<div class="min-w-1000px">
|
||||||
<div class="flex gap-3 justify-">
|
<div class="flex gap-3 justify-">
|
||||||
<button class="btn btn-error btn-sm" @click="deleteAll">全部删除</button>
|
<button class="btn btn-error btn-sm" @click="delAllDataDialog.showModal()">全部删除</button>
|
||||||
<div class="tooltip tooltip-bottom" data-tip="下载文件后,请在excel中填写数据,并保存为xlsx格式">
|
<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>
|
<a class="no-underline btn btn-secondary btn-sm" download="人口登记表.xlsx" target="_blank"
|
||||||
|
href="/log-lottery/人口登记表.xlsx">下载模板</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<label for="explore">
|
<label for="explore">
|
||||||
@@ -105,6 +174,8 @@ onMounted(() => {
|
|||||||
<!-- <button class="btn btn-primary btn-sm">上传excel</button> -->
|
<!-- <button class="btn btn-primary btn-sm">上传excel</button> -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<button class="btn btn-error btn-sm" @click="resetDataDialog.showModal()">重置数据</button>
|
||||||
|
<button class="btn btn-accent btn-sm" @click="exportData">导出结果</button>
|
||||||
<div>
|
<div>
|
||||||
<span>中奖人数:</span>
|
<span>中奖人数:</span>
|
||||||
<span>{{ alreadyPersonList.length }}</span>
|
<span>{{ alreadyPersonList.length }}</span>
|
||||||
|
|||||||
@@ -1,13 +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 { ref } from 'vue';
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
|
import { IPersonConfig } from '@/types/storeType';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
|
||||||
|
|
||||||
const personConfig = useStore().personConfig
|
const personConfig = useStore().personConfig
|
||||||
|
|
||||||
const { getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
|
||||||
// const personList = ref<any[]>(
|
// const personList = ref<any[]>(
|
||||||
// alreadyPersonList
|
// alreadyPersonList
|
||||||
// )
|
// )
|
||||||
@@ -16,11 +17,57 @@ const { getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
|
|||||||
// const deleteAll = () => {
|
// const deleteAll = () => {
|
||||||
// personConfig.deleteAllPerson()
|
// personConfig.deleteAllPerson()
|
||||||
// }
|
// }
|
||||||
const handleMoveNotPerson=(row:any)=>{
|
|
||||||
|
const isDetail = ref(false)
|
||||||
|
const handleMoveNotPerson = (row: IPersonConfig) => {
|
||||||
personConfig.moveAlreadyToNot(row)
|
personConfig.moveAlreadyToNot(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tableColumns = [
|
const tableColumnsList = [
|
||||||
|
{
|
||||||
|
label: '编号',
|
||||||
|
props: 'uid',
|
||||||
|
sort: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '姓名',
|
||||||
|
props: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '部门',
|
||||||
|
props: 'department',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '身份',
|
||||||
|
props: 'identity',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '奖品',
|
||||||
|
props: 'prizeName',
|
||||||
|
sort: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '操作',
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
label: '移入未中奖名单',
|
||||||
|
type: 'btn-info',
|
||||||
|
onClick: (row: IPersonConfig) => {
|
||||||
|
handleMoveNotPerson(row)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// label: '删除',
|
||||||
|
// type: 'btn-error',
|
||||||
|
// onClick: (row: any) => {
|
||||||
|
// console.log('删除:', row)
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const tableColumnsDetail = [
|
||||||
{
|
{
|
||||||
label: '编号',
|
label: '编号',
|
||||||
props: 'uid',
|
props: 'uid',
|
||||||
@@ -54,17 +101,10 @@ const tableColumns = [
|
|||||||
{
|
{
|
||||||
label: '移入未中奖名单',
|
label: '移入未中奖名单',
|
||||||
type: 'btn-info',
|
type: 'btn-info',
|
||||||
onClick: (row: any) => {
|
onClick: (row: IPersonConfig) => {
|
||||||
handleMoveNotPerson(row)
|
handleMoveNotPerson(row)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: '删除',
|
|
||||||
type: 'btn-error',
|
|
||||||
onClick: (row: any) => {
|
|
||||||
console.log('删除:', row)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -73,14 +113,24 @@ const tableColumns = [
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="overflow-y-auto">
|
<div class="overflow-y-auto">
|
||||||
<div class="flex justify-start gap-3">
|
<div class="flex items-center justify-start gap-10">
|
||||||
<!-- <button class="btn btn-error btn-sm" @click="deleteAll">全部删除</button> -->
|
<!-- <button class="btn btn-error btn-sm" @click="deleteAll">全部删除</button> -->
|
||||||
<div>
|
<div>
|
||||||
<span>中奖人数:</span>
|
<span>中奖人数:</span>
|
||||||
<span>{{ alreadyPersonList.length }}</span>
|
<span>{{ alreadyPersonList.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<div class="form-control">
|
||||||
|
<label class="cursor-pointer label">
|
||||||
|
<span class="label-text">详细信息:</span>
|
||||||
|
<input type="checkbox" class="border-solid toggle toggle-primary border-1" v-model="isDetail" />
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<DaiysuiTable :tableColumns="tableColumns" :data="alreadyPersonList"></DaiysuiTable>
|
</div>
|
||||||
|
</div>
|
||||||
|
<DaiysuiTable v-if="!isDetail" :tableColumns="tableColumnsList" :data="alreadyPersonList"></DaiysuiTable>
|
||||||
|
|
||||||
|
<DaiysuiTable v-if="isDetail" :tableColumns="tableColumnsDetail" :data="alreadyPersonDetail"></DaiysuiTable>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<script setup lang='ts'>
|
<script setup lang='ts'>
|
||||||
import { ref, onMounted, watch } from 'vue'
|
import { ref, onMounted, watch } from 'vue'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
|
import { IPrizeConfig } from '@/types/storeType'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import { IPrizeConfig } from '@/types/prizeConfig';
|
|
||||||
|
|
||||||
const imageDbStore = localforage.createInstance({
|
const imageDbStore = localforage.createInstance({
|
||||||
name: 'imgStore'
|
name: 'imgStore'
|
||||||
@@ -51,7 +51,7 @@ const getImageDbStore = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const sort = (item: any, isUp: number) => {
|
const sort = (item: IPrizeConfig, isUp: number) => {
|
||||||
const itemIndex = prizeList.value.indexOf(item)
|
const itemIndex = prizeList.value.indexOf(item)
|
||||||
if (isUp == 1) {
|
if (isUp == 1) {
|
||||||
prizeList.value.splice(itemIndex, 1)
|
prizeList.value.splice(itemIndex, 1)
|
||||||
@@ -70,7 +70,7 @@ const delAll = async () => {
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getImageDbStore()
|
getImageDbStore()
|
||||||
})
|
})
|
||||||
watch(() => prizeList, (val:any) => {
|
watch(() => prizeList.value, (val:IPrizeConfig[]) => {
|
||||||
prizeConfig.setPrizeConfig(val)
|
prizeConfig.setPrizeConfig(val)
|
||||||
}, { deep: true })
|
}, { deep: true })
|
||||||
</script>
|
</script>
|
||||||
@@ -136,18 +136,21 @@ watch(() => prizeList, (val:any) => {
|
|||||||
<span class="label-text">图片</span>
|
<span class="label-text">图片</span>
|
||||||
</div>
|
</div>
|
||||||
<select class="w-full max-w-xs select select-warning select-sm" v-model="item.picture">
|
<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:''}"><span>❌</span></option>
|
||||||
<option disabled selected>选择一张图片</option>
|
<option disabled selected>选择一张图片</option>
|
||||||
<option v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{ picItem.name }}
|
<option v-for="picItem in localImageList" :key="picItem.id" :value="picItem">{{ picItem.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="w-full max-w-xs mb-10 form-control">
|
<!-- <label class="w-full max-w-xs mb-10 form-control">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">展示在主界面</span>
|
<span class="label-text">展示在主界面</span>
|
||||||
</div>
|
</div>
|
||||||
<input type="checkbox" :checked="item.isShow" @change="item.isShow = !item.isShow"
|
<input type="checkbox" :checked="item.isShow" @change="item.isShow = !item.isShow"
|
||||||
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
|
||||||
</label>
|
</label> -->
|
||||||
<!-- <label class="w-full max-w-xs mb-10 form-control">
|
<!-- <label class="w-full max-w-xs mb-10 form-control">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<span class="label-text">抽取次数</span>
|
<span class="label-text">抽取次数</span>
|
||||||
|
|||||||
@@ -64,26 +64,17 @@ const skip = (path: string) => {
|
|||||||
</div>
|
</div>
|
||||||
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
|
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
|
||||||
<nav class="grid grid-flow-col gap-4">
|
<nav class="grid grid-flow-col gap-4">
|
||||||
<a class="link link-hover">About us</a>
|
<a class="link link-hover">行有不得,反求诸己</a>
|
||||||
<a class="link link-hover">Contact</a>
|
|
||||||
<a class="link link-hover">Jobs</a>
|
|
||||||
<a class="link link-hover">Press kit</a>
|
|
||||||
</nav>
|
</nav>
|
||||||
<nav>
|
<nav>
|
||||||
<div class="grid grid-flow-col gap-4">
|
<div class="grid grid-flow-col gap-4">
|
||||||
<a href="https://github.com/LOG1997/log-lottery" target="_blank" class="cursor-pointer">
|
<a href="https://github.com/LOG1997/log-lottery" target="_blank" class="cursor-pointer text-inherit">
|
||||||
<svg-icon name="github"></svg-icon>
|
<svg-icon name="github"></svg-icon>
|
||||||
</a>
|
</a>
|
||||||
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
|
<a href="https://twitter.com/TaborSwift" target="_blank" class="cursor-pointer "><svg-icon name="twitter"></svg-icon></a>
|
||||||
<path
|
<a href="https://www.instagram.com/log.z1997/" target="_blank" class="cursor-pointer ">
|
||||||
d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z">
|
<svg-icon name="instagram"></svg-icon>
|
||||||
</path>
|
</a>
|
||||||
</svg></a>
|
|
||||||
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
|
|
||||||
<path
|
|
||||||
d="M9 8h-3v4h3v12h5v-12h3.642l.358-4h-4v-1.667c0-.955.192-1.333 1.115-1.333h2.885v-5h-3.808c-3.596 0-5.192 1.583-5.192 4.615v3.385z">
|
|
||||||
</path>
|
|
||||||
</svg></a>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<aside>
|
<aside>
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import { ref, onMounted } from 'vue'
|
|||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
|
|
||||||
|
import ImageSync from '@/components/ImageSync/index.vue'
|
||||||
|
import defaultPrizeImage from '@/assets/images/龙.png'
|
||||||
|
|
||||||
const prizeConfig = useStore().prizeConfig
|
const prizeConfig = useStore().prizeConfig
|
||||||
const globalConfig = useStore().globalConfig
|
const globalConfig = useStore().globalConfig
|
||||||
const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
const { getPrizeConfig: localPrizeList, getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
||||||
@@ -39,7 +42,8 @@ onMounted(() => {
|
|||||||
class="relative flex flex-row items-center justify-between w-64 h-20 shadow-xl card bg-base-100" v-if="item.isShow">
|
class="relative flex flex-row items-center justify-between w-64 h-20 shadow-xl card bg-base-100" v-if="item.isShow">
|
||||||
<div v-if="item.isUsed" class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"></div>
|
<div v-if="item.isUsed" class="absolute z-50 w-full h-full bg-gray-800/70 item-mask rounded-xl"></div>
|
||||||
<figure class="w-10 h-10 rounded-xl">
|
<figure class="w-10 h-10 rounded-xl">
|
||||||
<img :src="item.picture.url" alt="Shoes" class="object-cover h-full rounded-xl" />
|
<ImageSync v-if="item.picture.url" :imgItem="item.picture"></ImageSync>
|
||||||
|
<img v-else :src="defaultPrizeImage" alt="Prize" class="object-cover h-full rounded-xl" />
|
||||||
</figure>
|
</figure>
|
||||||
<div class="items-center p-0 text-center card-body">
|
<div class="items-center p-0 text-center card-body">
|
||||||
<h2 class="p-0 m-0 card-title">{{ item.name }}</h2>
|
<h2 class="p-0 m-0 card-title">{{ item.name }}</h2>
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ import { useElementStyle, useElementPosition } from '@/hooks/useElement'
|
|||||||
import StarsBackground from '@/components/StarsBackground/index.vue'
|
import StarsBackground from '@/components/StarsBackground/index.vue'
|
||||||
import confetti from 'canvas-confetti'
|
import confetti from 'canvas-confetti'
|
||||||
import { filterData } from '@/utils'
|
import { filterData } from '@/utils'
|
||||||
import * as THREE from 'three'
|
// import * as THREE from 'three'
|
||||||
import {
|
import {Scene,PerspectiveCamera,Object3D,Vector3} from 'three'
|
||||||
CSS3DRenderer, CSS3DObject
|
// import {
|
||||||
} from 'three/examples/jsm/renderers/CSS3DRenderer.js';
|
// CSS3DRenderer, CSS3DObject
|
||||||
import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js';
|
// } from 'three/examples/jsm/renderers/CSS3DRenderer.js';
|
||||||
import TWEEN from 'three/examples/jsm/libs/tween.module.js';
|
import {CSS3DRenderer, CSS3DObject} from 'three-css3d'
|
||||||
|
// import { TrackballControls } from 'three/examples/jsm/controls/TrackballControls.js';
|
||||||
|
import TrackballControls from 'three-trackballcontrols';
|
||||||
|
// import TWEEN from 'three/examples/jsm/libs/tween.module.js';
|
||||||
|
import * as TWEEN from '@tweenjs/tween.js'
|
||||||
import useStore from '@/store'
|
import useStore from '@/store'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
@@ -28,7 +32,6 @@ const { getCurrentPrize: currentPrize } = storeToRefs(prizeConfig)
|
|||||||
const { getTopTitle: topTitle, getCardColor: cardColor, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount } = storeToRefs(globalConfig)
|
const { getTopTitle: topTitle, getCardColor: cardColor, getTextColor: textColor, getLuckyColor: luckyColor, getCardSize: cardSize, getTextSize: textSize, getRowCount: rowCount } = storeToRefs(globalConfig)
|
||||||
const tableData = ref<any[]>([])
|
const tableData = ref<any[]>([])
|
||||||
// const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value))))
|
// const tableData = ref<any[]>(JSON.parse(JSON.stringify(alreadyPersonList.value)).concat(JSON.parse(JSON.stringify(notPersonList.value))))
|
||||||
|
|
||||||
const currentStatus = ref(0) // 0为初始状态, 1为抽奖准备状态,2为抽奖中状态,3为抽奖结束状态
|
const currentStatus = ref(0) // 0为初始状态, 1为抽奖准备状态,2为抽奖中状态,3为抽奖结束状态
|
||||||
const ballRotationY = ref(0)
|
const ballRotationY = ref(0)
|
||||||
const containerRef = ref<HTMLElement>()
|
const containerRef = ref<HTMLElement>()
|
||||||
@@ -80,8 +83,8 @@ const init = () => {
|
|||||||
const farPlane = 10000;
|
const farPlane = 10000;
|
||||||
const WebGLoutput = containerRef.value
|
const WebGLoutput = containerRef.value
|
||||||
|
|
||||||
scene.value = new THREE.Scene();
|
scene.value = new Scene();
|
||||||
camera.value = new THREE.PerspectiveCamera(felidView, aspect, nearPlane, farPlane);
|
camera.value = new PerspectiveCamera(felidView, aspect, nearPlane, farPlane);
|
||||||
camera.value.position.z = cameraZ.value
|
camera.value.position.z = cameraZ.value
|
||||||
renderer.value = new CSS3DRenderer()
|
renderer.value = new CSS3DRenderer()
|
||||||
renderer.value.setSize(width, height * 0.9)
|
renderer.value.setSize(width, height * 0.9)
|
||||||
@@ -138,7 +141,7 @@ const init = () => {
|
|||||||
const tableLen = tableData.value.length;
|
const tableLen = tableData.value.length;
|
||||||
|
|
||||||
for (let i = 0; i < tableLen; i++) {
|
for (let i = 0; i < tableLen; i++) {
|
||||||
const object = new THREE.Object3D();
|
const object = new Object3D();
|
||||||
|
|
||||||
object.position.x = tableData.value[i].x * (cardSize.value.width + 40) - rowCount.value * 90;
|
object.position.x = tableData.value[i].x * (cardSize.value.width + 40) - rowCount.value * 90;
|
||||||
object.position.y = -tableData.value[i].y * (cardSize.value.height + 20) + 1000;
|
object.position.y = -tableData.value[i].y * (cardSize.value.height + 20) + 1000;
|
||||||
@@ -151,12 +154,12 @@ const init = () => {
|
|||||||
function createSphereVertices() {
|
function createSphereVertices() {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const objLength = objects.value.length;
|
const objLength = objects.value.length;
|
||||||
const vector = new THREE.Vector3();
|
const vector = new Vector3();
|
||||||
|
|
||||||
for (; i < objLength; ++i) {
|
for (; i < objLength; ++i) {
|
||||||
let phi = Math.acos(-1 + (2 * i) / objLength);
|
let phi = Math.acos(-1 + (2 * i) / objLength);
|
||||||
let theta = Math.sqrt(objLength * Math.PI) * phi;
|
let theta = Math.sqrt(objLength * Math.PI) * phi;
|
||||||
const object = new THREE.Object3D();
|
const object = new Object3D();
|
||||||
|
|
||||||
object.position.x = 800 * Math.cos(theta) * Math.sin(phi);
|
object.position.x = 800 * Math.cos(theta) * Math.sin(phi);
|
||||||
object.position.y = 800 * Math.sin(theta) * Math.sin(phi);
|
object.position.y = 800 * Math.sin(theta) * Math.sin(phi);
|
||||||
@@ -171,12 +174,12 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
function createHelixVertices() {
|
function createHelixVertices() {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
const vector = new THREE.Vector3();
|
const vector = new Vector3();
|
||||||
const objLength = objects.value.length;
|
const objLength = objects.value.length;
|
||||||
for (; i < objLength; ++i) {
|
for (; i < objLength; ++i) {
|
||||||
let phi = i * 0.213 + Math.PI;
|
let phi = i * 0.213 + Math.PI;
|
||||||
|
|
||||||
const object = new THREE.Object3D();
|
const object = new Object3D();
|
||||||
|
|
||||||
object.position.x = 800 * Math.sin(phi);
|
object.position.x = 800 * Math.sin(phi);
|
||||||
object.position.y = -(i * 8) + 450;
|
object.position.y = -(i * 8) + 450;
|
||||||
@@ -378,14 +381,13 @@ const stopLottery = async () => {
|
|||||||
rollBall(0, 1)
|
rollBall(0, 1)
|
||||||
currentStatus.value = 0
|
currentStatus.value = 0
|
||||||
// 抽奖池是否为全体人员
|
// 抽奖池是否为全体人员
|
||||||
// const personPool=currentPrize.value.isAll?
|
const personPool = currentPrize.value.isAll ? allPersonList.value : notPersonList.value
|
||||||
|
// const notPersonListLength = personPool.length;
|
||||||
// const notPersonListLength = notPersonList.value.length;
|
|
||||||
// 每次最多抽十个
|
// 每次最多抽十个
|
||||||
let luckyCount = 10
|
let luckyCount = 10
|
||||||
const leftover = currentPrize.value.count - currentPrize.value.isUsedCount
|
const leftover = currentPrize.value.count - currentPrize.value.isUsedCount
|
||||||
leftover < luckyCount ? luckyCount = leftover : luckyCount
|
leftover < luckyCount ? luckyCount = leftover : luckyCount
|
||||||
if (notPersonList.value.length < leftover) {
|
if (personPool.length < leftover) {
|
||||||
toast.open({
|
toast.open({
|
||||||
message: '抽奖人数不够',
|
message: '抽奖人数不够',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@@ -396,24 +398,25 @@ const stopLottery = async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let i = 0; i < luckyCount; i++) {
|
for (let i = 0; i < luckyCount; i++) {
|
||||||
if (notPersonList.value.length > 0) {
|
if (personPool.length > 0) {
|
||||||
const randomIndex = Math.round(Math.random() * notPersonList.value.length - 1)
|
const randomIndex = Math.round(Math.random() * (personPool.length-1))
|
||||||
luckyTargets.value.push(notPersonList.value[randomIndex])
|
luckyTargets.value.push(personPool[randomIndex])
|
||||||
// console.log(
|
console.log(
|
||||||
// 'leftover:', leftover, '\n',
|
'leftover:', leftover, '\n',
|
||||||
// 'luckyCount', luckyCount, '\n',
|
'luckyCount', luckyCount, '\n',
|
||||||
// 'currentPrize.value.isUsedCount', currentPrize.value.isUsedCount, '\n',
|
'currentPrize.value.isUsedCount', currentPrize.value.isUsedCount, '\n',
|
||||||
// 'randomIndex', randomIndex, '\n',
|
'randomIndex', randomIndex, '\n',
|
||||||
// 'notPersonList.value.length - 1', notPersonList.value.length - 1, '\n',
|
'personPool.length - 1', personPool.length - 1, '\n',
|
||||||
// 'notPersonList.value[randomIndex]', notPersonList.value[randomIndex], '\n',
|
'personPool[randomIndex]', personPool[randomIndex], '\n',
|
||||||
// 'cadd id:', notPersonList.value[randomIndex].id
|
)
|
||||||
// )
|
console.log(
|
||||||
let LuckyCard = objects.value[notPersonList.value[randomIndex].id]
|
'cadd id:', personPool[randomIndex].id)
|
||||||
luckyCardList.value.push(LuckyCard)
|
let luckyCard = objects.value[personPool[randomIndex].id]
|
||||||
|
luckyCardList.value.push(luckyCard)
|
||||||
|
|
||||||
notPersonList.value.splice(randomIndex, 1)
|
personPool.splice(randomIndex, 1)
|
||||||
// console.log(
|
// console.log(
|
||||||
// 'objects.value[notPersonList.value[randomIndex].id]', LuckyCard
|
// 'objects.value[personPool[randomIndex].id]', LuckyCard
|
||||||
// )
|
// )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -443,16 +446,16 @@ const stopLottery = async () => {
|
|||||||
resetCamera()
|
resetCamera()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
currentPrize.value.isUsedCount += luckyCount
|
// currentPrize.value.isUsedCount += luckyCount
|
||||||
if (currentPrize.value.isUsedCount >= currentPrize.value.count) {
|
// if (currentPrize.value.isUsedCount >= currentPrize.value.count) {
|
||||||
currentPrize.value.isUsed = true
|
// currentPrize.value.isUsed = true
|
||||||
}
|
// }
|
||||||
// luckyCardList.value = []
|
// luckyCardList.value = []
|
||||||
|
|
||||||
personConfig.addAlreadyPersonList(luckyTargets.value, currentPrize.value)
|
// personConfig.addAlreadyPersonList(luckyTargets.value, currentPrize.value)
|
||||||
prizeConfig.updatePrizeConfig(currentPrize.value)
|
// prizeConfig.updatePrizeConfig(currentPrize.value)
|
||||||
|
|
||||||
prizeConfig.setCurrentPrize(currentPrize.value)
|
// prizeConfig.setCurrentPrize(currentPrize.value)
|
||||||
luckyTargets.value = []
|
luckyTargets.value = []
|
||||||
}
|
}
|
||||||
// 庆祝动画
|
// 庆祝动画
|
||||||
@@ -588,11 +591,13 @@ onUnmounted(() => {
|
|||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.start {
|
.start {
|
||||||
// 居中
|
// 居中
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-start {
|
.btn-start {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -764,6 +769,7 @@ strong {
|
|||||||
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-end {
|
.btn-end {
|
||||||
-webkit-animation: pulsate-fwd 0.9s ease-in-out infinite both;
|
-webkit-animation: pulsate-fwd 0.9s ease-in-out infinite both;
|
||||||
animation: pulsate-fwd 0.9s ease-in-out infinite both;
|
animation: pulsate-fwd 0.9s ease-in-out infinite both;
|
||||||
|
|||||||
1
src/vite-env.d.ts
vendored
1
src/vite-env.d.ts
vendored
@@ -7,3 +7,4 @@ declare module '*.vue' {
|
|||||||
}
|
}
|
||||||
|
|
||||||
declare module 'sparticles'
|
declare module 'sparticles'
|
||||||
|
declare module 'three-trackballcontrols'
|
||||||
|
|||||||
Reference in New Issue
Block a user