feat: feat

This commit is contained in:
ex_zhangwenlei@exiot.cmcc
2024-01-11 00:11:27 +08:00
parent 3283a2d975
commit 3e429b95a2
32 changed files with 793 additions and 1377 deletions

View File

@@ -97,7 +97,9 @@ watch(() => formData.value.rowCount, () => {
formErr.value.rowCount = err.issues[0].message
})
})
watch(topTitleValue,(val)=>{
globalConfig.setTopTitle(val)
}),
watch(themeValue, (val: any) => {
const selectedThemeDetail = daisyuiThemeList.value[val]

View File

@@ -1,6 +1,7 @@
<script setup lang='ts'>
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 useStore from '@/store'
import { storeToRefs } from 'pinia'
@@ -14,14 +15,14 @@ const imgUploadToast = ref(0) //0是不显示1是成功2是失败,3是不
const imageDbStore = localforage.createInstance({
name: 'imgStore'
})
const handleFileChange = async (e: any) => {
const isImage= /image*/.test(e.target.files[0].type)
const handleFileChange = async (e: Event) => {
const isImage= /image*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
if (!isImage) {
imgUploadToast.value = 3
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)
.then(() => {
imgUploadToast.value = 1
@@ -45,7 +46,7 @@ const getImageDbStore =async () => {
}
}
const removeImage=(item:any)=>{
const removeImage=(item:IImage)=>{
if(item.url=='Storage'){
imageDbStore.removeItem(item.id).then(() => {
globalConfig.removeImage(item.id)
@@ -91,8 +92,8 @@ watch(() => imgUploadToast.value, (val) => {
<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 v-else :imgItem="item"></ImageSync>
<!-- <img v-if="item.url!=='Storage'" :src="item.url" alt="Avatar Tailwind CSS Component" /> -->
<ImageSync :imgItem="item"></ImageSync>
</div>
</div>
<div class="w-64">

View File

@@ -1,7 +1,8 @@
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
import {storeToRefs } from 'pinia'
import { readMusic } from '@/utils/file'
import { IMusic } from '@/types/storeType';
import { readFileData } from '@/utils/file'
import useStore from '@/store';
import localforage from 'localforage'
@@ -15,11 +16,11 @@ const globalConfig = useStore().globalConfig
const { getMusicList: localMusicList } = storeToRefs(globalConfig);
const limitType = ref('audio/*')
const localMusicListValue = ref(localMusicList)
const play = async (item: any) => {
const play = async (item: IMusic) => {
globalConfig.setCurrentMusic(item,false)
}
const deleteMusic = (item: any) => {
const deleteMusic = (item: IMusic) => {
globalConfig.removeMusic(item.id)
audioDbStore.removeItem(item.name)
// setTimeout(()=>{
@@ -46,14 +47,14 @@ const getMusicDbStore = async () => {
})
}
}
const handleFileChange = async (e: any) => {
const isAudio = /audio*/.test(e.target.files[0].type)
const handleFileChange = async (e: Event) => {
const isAudio = /audio*/.test(((e.target as HTMLInputElement).files as FileList)[0].type)
if (!isAudio) {
audioUploadToast.value = 3
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)
.then(() => {
audioUploadToast.value = 1

View File

@@ -2,23 +2,26 @@
<script setup lang='ts'>
import { ref, onMounted } from 'vue';
import useStore from '@/store'
import { IPersonConfig } from '@/types/storeType';
import { storeToRefs } from 'pinia'
import * as XLSX from 'xlsx'
import { readFile } from '@/utils/file'
import { readFileBinary } from '@/utils/file'
import { filterData, addOtherInfo } from '@/utils'
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
const personConfig = useStore().personConfig
const globalConfig = useStore().globalConfig
const { getAllPersonList: allPersonList,getAlreadyPersonList:alreadyPersonList } = storeToRefs(personConfig)
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
const { getRowCount: rowCount } = storeToRefs(globalConfig)
const limitType = '.xlsx,.xls'
const excelData = ref<any[]>([])
// const personList = ref<any[]>([])
const resetDataDialog=ref()
const delAllDataDialog=ref()
const handleFileChange = async (e: any) => {
let dataBinary = await readFile(e.target.files[0])
const handleFileChange = async (e: Event) => {
let dataBinary = await readFileBinary(((e.target as HTMLInputElement).files as FileList)[0]!)
let workBook = XLSX.read(dataBinary, { type: 'binary', cellDates: true })
let workSheet = workBook.Sheets[workBook.SheetNames[0]]
excelData.value = XLSX.utils.sheet_to_json(workSheet)
@@ -27,12 +30,51 @@ const handleFileChange = async (e: any) => {
personConfig.resetPerson()
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 = () => {
personConfig.deleteAllPerson()
}
const delPersonItem = (row: any) => {
const delPersonItem = (row: IPersonConfig) => {
personConfig.deletePerson(row)
}
@@ -56,7 +98,7 @@ const tableColumns = [
{
label: '是否已中奖',
props: 'isWin',
formatValue(row: any) {
formatValue(row: IPersonConfig) {
return row.isWin ? '是' : '否'
}
},
@@ -73,7 +115,7 @@ const tableColumns = [
{
label: '删除',
type: 'btn-error',
onClick: (row: any) => {
onClick: (row: IPersonConfig) => {
delPersonItem(row)
}
},
@@ -86,11 +128,38 @@ onMounted(() => {
</script>
<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="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格式">
<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 class="">
<label for="explore">
@@ -105,6 +174,8 @@ onMounted(() => {
<!-- <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>

View File

@@ -1,13 +1,14 @@
<!-- eslint-disable vue/no-parsing-error -->
<script setup lang='ts'>
// import { ref } from 'vue';
import { ref } from 'vue';
import useStore from '@/store'
import { IPersonConfig } from '@/types/storeType';
import { storeToRefs } from 'pinia';
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
const personConfig = useStore().personConfig
const { getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
const { getAlreadyPersonList: alreadyPersonList, getAlreadyPersonDetail: alreadyPersonDetail } = storeToRefs(personConfig)
// const personList = ref<any[]>(
// alreadyPersonList
// )
@@ -16,15 +17,17 @@ const { getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
// const deleteAll = () => {
// personConfig.deleteAllPerson()
// }
const handleMoveNotPerson=(row:any)=>{
const isDetail = ref(false)
const handleMoveNotPerson = (row: IPersonConfig) => {
personConfig.moveAlreadyToNot(row)
}
const tableColumns = [
const tableColumnsList = [
{
label: '编号',
props: 'uid',
sort:true
sort: true
},
{
label: '姓名',
@@ -39,9 +42,53 @@ const tableColumns = [
props: 'identity',
},
{
label:'奖品',
props:'prizeName',
sort:true
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: '编号',
props: 'uid',
sort: true
},
{
label: '姓名',
props: 'name',
},
{
label: '部门',
props: 'department',
},
{
label: '身份',
props: 'identity',
},
{
label: '奖品',
props: 'prizeName',
sort: true
},
{
label: '中奖时间',
@@ -54,17 +101,10 @@ const tableColumns = [
{
label: '移入未中奖名单',
type: 'btn-info',
onClick: (row: any) => {
onClick: (row: IPersonConfig) => {
handleMoveNotPerson(row)
}
},
{
label: '删除',
type: 'btn-error',
onClick: (row: any) => {
console.log('删除:', row)
}
},
]
},
@@ -73,14 +113,24 @@ const tableColumns = [
<template>
<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> -->
<div>
<span>中奖人数</span>
<span>{{ alreadyPersonList.length }}</span>
</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>
</div>
<DaiysuiTable :tableColumns="tableColumns" :data="alreadyPersonList"></DaiysuiTable>
<DaiysuiTable v-if="!isDetail" :tableColumns="tableColumnsList" :data="alreadyPersonList"></DaiysuiTable>
<DaiysuiTable v-if="isDetail" :tableColumns="tableColumnsDetail" :data="alreadyPersonDetail"></DaiysuiTable>
</div>
</template>

View File

@@ -1,9 +1,9 @@
<script setup lang='ts'>
import { ref, onMounted, watch } from 'vue'
import useStore from '@/store'
import { IPrizeConfig } from '@/types/storeType'
import { storeToRefs } from 'pinia'
import localforage from 'localforage'
import { IPrizeConfig } from '@/types/prizeConfig';
const imageDbStore = localforage.createInstance({
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)
if (isUp == 1) {
prizeList.value.splice(itemIndex, 1)
@@ -70,7 +70,7 @@ const delAll = async () => {
onMounted(() => {
getImageDbStore()
})
watch(() => prizeList, (val:any) => {
watch(() => prizeList.value, (val:IPrizeConfig[]) => {
prizeConfig.setPrizeConfig(val)
}, { deep: true })
</script>
@@ -136,18 +136,21 @@ watch(() => prizeList, (val:any) => {
<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:''}"><span></span></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">
<!-- <label class="w-full max-w-xs mb-10 form-control">
<div class="label">
<span class="label-text">展示在主界面</span>
</div>
<input type="checkbox" :checked="item.isShow" @change="item.isShow = !item.isShow"
class="mt-2 border-solid checkbox checkbox-secondary border-1" />
</label>
</label> -->
<!-- <label class="w-full max-w-xs mb-10 form-control">
<div class="label">
<span class="label-text">抽取次数</span>

View File

@@ -64,26 +64,17 @@ const skip = (path: string) => {
</div>
<footer class="p-10 rounded footer footer-center bg-base-200 text-base-content">
<nav class="grid grid-flow-col gap-4">
<a class="link link-hover">About us</a>
<a class="link link-hover">Contact</a>
<a class="link link-hover">Jobs</a>
<a class="link link-hover">Press kit</a>
<a class="link link-hover">行有不得反求诸己</a>
</nav>
<nav>
<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>
</a>
<a><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" class="fill-current">
<path
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">
</path>
</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>
<a href="https://twitter.com/TaborSwift" target="_blank" class="cursor-pointer "><svg-icon name="twitter"></svg-icon></a>
<a href="https://www.instagram.com/log.z1997/" target="_blank" class="cursor-pointer ">
<svg-icon name="instagram"></svg-icon>
</a>
</div>
</nav>
<aside>