Confilct dev date 12 22 (#131)

* fix(home): 🐛 解决多次切换路由后页面卡顿的问题 #96

卸载路由时清除requestAnimationFrame

* feat:  文件存储使用Blob格式

* style: 💄 修改部分类型any为具体类型

* feat:  界面设置中模块使用瀑布流布局 #96

* fix: 🐛 md文档更换文件夹解决控制台警告

* style: 💄 switch按钮改回使用daisyui组件

* refactor: ♻️ 所有人员列表提取tableColumn

* style: 💄 奖项列表中的图片类型修复

* fix(globalConfig): 修复当前音乐项类型缺失问题

* feat:  single person not done

* feat:  可添加单人 #96

* build(.gitignore): 添加 auto-imports.d.ts 到忽略文件

* fix: 🐛 上传、下载excel文件时修复路径错误

打包成应用和网页端的baseUrl不一样,使用环境变量来表示

* fix: 🐛 导入人员列表时处理有值为空的情况

* style: 💄 改变toaster的组件

* fix: 🐛 上传文件、解析数据与存储/读取数据的处理

、
This commit is contained in:
LOG1997
2025-12-22 17:28:10 +08:00
committed by GitHub
parent 5b8682bb7c
commit f8098a9737
18 changed files with 254 additions and 179 deletions

View File

@@ -0,0 +1,46 @@
<script setup lang='ts'>
defineProps<{
addOnePersonDrawerRef: any
addOnePerson: (addOnePersonDrawerRef: any, event: any) => void
}>()
const singlePersonData = defineModel<any>('singlePersonData', { required: true })
</script>
<template>
<form class="fieldset rounded-box w-xs p-4" @submit="(e) => addOnePerson(addOnePersonDrawerRef, e)">
<label class="fieldset">
<span class="label">编号</span>
<input v-model="singlePersonData.uid" type="text" class="input validator" placeholder="编号">
</label>
<fieldset class="fieldset">
<label class="label" required>姓名<span class="text-red-500">*</span></label>
<input v-model="singlePersonData.name" type="text" class="input validator" placeholder="姓名" required minlength="1">
<p class="validator-hint hidden">
请填写姓名
</p>
</fieldset>
<label class="fieldset">
<span class="label">部门</span>
<input v-model="singlePersonData.department" type="text" class="input validator" placeholder="部门">
</label>
<label class="fieldset">
<span class="label">头像</span>
<input v-model="singlePersonData.avatar" type="text" class="input validator" placeholder="头像">
</label>
<label class="fieldset">
<span class="label">身份</span>
<input v-model="singlePersonData.identity" type="text" class="input validator" placeholder="身份">
</label>
<button class="btn btn-neutral mt-4" type="submit">
确定
</button>
<button class="btn btn-ghost mt-1" type="reset" @click="addOnePersonDrawerRef.closeDrawer()">
取消
</button>
</form>
</template>
<style scoped>
</style>

View File

@@ -10,8 +10,8 @@ interface WorkerMessage {
let allData: any[] = []
function headersEqual(template: string[], actual: string[]): boolean {
return template.length === actual.length
&& template.every((value, index) => value === actual[index])
return template.length >= actual.length
&& actual.some(item => template.includes(item))
}
// 接收主线程消息

View File

@@ -4,13 +4,17 @@ import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import DaiysuiTable from '@/components/DaiysuiTable/index.vue'
import CustomDialog from '@/components/Dialog/index.vue'
import CustomDrawer from '@/components/Drawer/index.vue'
import PageHeader from '@/components/PageHeader/index.vue'
import SinglePersonContent from './components/SinglePerson.vue'
import { useViewModel } from './useViewModel'
const resetDataDialogRef = ref()
const delAllDataDialogRef = ref()
const exportInputFileRef = ref()
const { resetData, deleteAll, handleFileChange, exportData, alreadyPersonList, allPersonList, tableColumnList } = useViewModel({ exportInputFileRef })
const addOnePersonDrawerRef = ref()
const baseUrl = import.meta.env.BASE_URL
const { resetData, deleteAll, handleFileChange, exportData, addOnePerson, singlePersonData, alreadyPersonList, allPersonList, tableColumnList } = useViewModel({ exportInputFileRef })
const { t } = useI18n()
const limitType = '.xlsx,.xls'
</script>
@@ -28,6 +32,15 @@ const limitType = '.xlsx,.xls'
:desc="t('dialog.dialogDelAllPerson')"
:submit-func="deleteAll"
/>
<CustomDrawer ref="addOnePersonDrawerRef">
<template #content>
<SinglePersonContent
v-model:single-person-data="singlePersonData"
:add-one-person-drawer-ref="addOnePersonDrawerRef"
:add-one-person="addOnePerson"
/>
</template>
</CustomDrawer>
<div class="min-w-1000px">
<PageHeader :title="t('viewTitle.personManagement')">
@@ -39,7 +52,7 @@ const limitType = '.xlsx,.xls'
<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')}`"
:href="`${baseUrl}${t('data.xlsxName')}`"
>{{ t('button.downloadTemplate') }}</a>
</div>
<div class="">
@@ -60,6 +73,9 @@ const limitType = '.xlsx,.xls'
<button class="btn btn-accent btn-sm" @click="exportData">
{{ t('button.exportResult') }}
</button>
<button class="btn btn-neutral btn-sm" @click="addOnePersonDrawerRef.showDrawer()">
添加
</button>
<div>
<span>{{ t('table.luckyPeopleNumber') }}:</span>
<span>{{ alreadyPersonList.length }}</span>

View File

@@ -1,30 +1,43 @@
import type { Ref } from 'vue'
import type { IPersonConfig } from '@/types/storeType'
import { storeToRefs } from 'pinia'
import { inject } from 'vue'
import { toast } from 'vue-sonner'
import { v4 as uuidv4 } from 'uuid'
import { inject, ref, toRaw } from 'vue'
import { useToast } from 'vue-toast-notification'
import * as XLSX from 'xlsx'
import { loadingKey } from '@/components/Loading'
import i18n from '@/locales/i18n'
import useStore from '@/store'
import { addOtherInfo } from '@/utils'
import { readFileBinary, readLocalFileAsArraybuffer } from '@/utils/file'
import { tableColumns } from './columns'
import ImportExcelWorker from './importExcel.worker?worker'
type IBasePersonConfig = Pick<IPersonConfig, 'uid' | 'name' | 'department' | 'identity' | 'avatar'>
export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<HTMLInputElement> }) {
const toast = useToast()
const worker: Worker | null = new ImportExcelWorker()
const loading = inject(loadingKey)
const personConfig = useStore().personConfig
const { getAllPersonList: allPersonList, getAlreadyPersonList: alreadyPersonList } = storeToRefs(personConfig)
const tableColumnList = tableColumns({ handleDeletePerson: delPersonItem })
const addPersonModalVisible = ref(false)
const singlePersonData = ref<IBasePersonConfig>({
uid: '',
name: '',
department: '',
avatar: '',
identity: '',
})
async function getExcelTemplateContent() {
const locale = i18n.global.locale.value
if (locale === 'zhCn') {
const templateData = await readLocalFileAsArraybuffer('/log-lottery/人口登记表-zhCn.xlsx')
const templateData = await readLocalFileAsArraybuffer(`${import.meta.env.BASE_URL}人口登记表-zhCn.xlsx`)
return templateData
}
else {
const templateData = await readLocalFileAsArraybuffer('/log-lottery/personListTemplate-en.xlsx')
const templateData = await readLocalFileAsArraybuffer(`${import.meta.env.BASE_URL}personListTemplate-en.xlsx`)
return templateData
}
}
@@ -53,7 +66,12 @@ export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<H
clearFileInput()
}
if (e.data.type === 'error') {
toast.warning(e.data.message || '导入错误')
toast.open({
message: e.data.message || '导入错误',
type: 'error',
position: 'top-right',
})
// toast.warning(e.data.message || '导入错误')
}
loading?.hide()
}
@@ -67,7 +85,7 @@ export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<H
exportInputFileRef.value.value = ''
}
}
/// 导出数据
// 导出数据
function exportData() {
let data = JSON.parse(JSON.stringify(allPersonList.value))
// 排除一些字段
@@ -120,6 +138,17 @@ export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<H
function delPersonItem(row: IPersonConfig) {
personConfig.deletePerson(row)
}
function addOnePerson(addOnePersonDrawerRef: any, event: any) {
event.preventDefault()
// 表单中的验证信息清除
const personData = addOtherInfo([toRaw(singlePersonData.value)])
personData[0].id = uuidv4()
personConfig.addOnePerson(personData)
// singlePersonData.value = {} as IBasePersonConfig
addOnePersonDrawerRef.closeDrawer()
singlePersonData.value = {} as IBasePersonConfig
}
return {
resetData,
deleteAll,
@@ -128,5 +157,8 @@ export function useViewModel({ exportInputFileRef }: { exportInputFileRef: Ref<H
alreadyPersonList,
allPersonList,
tableColumnList,
addOnePerson,
addPersonModalVisible,
singlePersonData,
}
}