Verwenden Sie vue3 + Ts + Vite + ElementPlus, um ein Lotterieprogramm zu implementieren

1. Beschreibung

  1. Dies ist ein Lotterieprogramm, das über vue3 + Ts + Vite + ElementPlus implementiert wird.
  2. Projektlink

2. Gesamtstruktur und Funktionsbeschreibung

  1. 左侧设置了奖品说明,每个奖项配有文字和图片简介. Insgesamt sind vier Auszeichnungen vergeben, nämlich 1 Sonderpreis, 2 erste Preise, 5 zweite Preise und 10 dritte Preise. (Derzeit ist die Anzahl der Plätze für jede Auszeichnung auf einen festen Wert festgelegt und wird später auf einen anpassbaren Wert festgelegt, damit Benutzer sie flexibel festlegen können.)
  2. 中间部分设置四个奖项的切换按钮,和“开始”抽奖的按钮。Klicken Sie auf „Start“, um an der Verlosung teilzunehmen. Die Namen der Personen, die an der Lotterie teilnehmen, werden zufällig auf dem Bildschirm angezeigt. Durch erneutes Klicken werden die Namen der Gewinner angezeigt und gleichzeitig gespeichert . Wenn das Kontingent für jede Auszeichnung ausgeschöpft ist, wird die Schaltfläche „Start“ ausgegraut. Wenn Sie nun auf die Lotterie klicken, wird die Meldung „Diese Auszeichnung wurde ausgelost“ angezeigt.
  3. 右侧设置了三个按钮,分别是:参与人员、抽奖记录、重新抽奖。
    • Teilnehmer: Stellen Sie Download-Vorlagen bereit, löschen Sie Daten und Benutzer können Daten anpassen und importieren.
    • Lotterie-Ziehungsprotokoll: Zeigt die Liste der Gewinner, Abteilungen und Auszeichnungen.
    • Erneut ziehen: Setzen Sie den vorherigen Lotteriedatensatz zurück. Er kann vollständig zurückgesetzt werden.
  4. 说明:目前的设置是每个人只能有一次中奖机会,即中奖后不能在中奖另一种奖项。

3. Datenspeicherung

无后台,纯前端实现Darüber hinaus ist es notwendig, den Browser zu aktualisieren und zu schließen, ohne dass Daten verloren gehen. Bei Verwendung von localStorage sind die in localStorage gespeicherten Daten dauerhaft und ändern sich nicht durch das Aktualisieren oder Schließen des Browsers (es sei denn, sie werden manuell und absichtlich gelöscht).

4. Beschreibung der Hauptfunktion

  1. Auszeichnungswechsel:
 <el-radio-group v-model="prizeValue" class="radioGroup" @change="changePrizeType">
      <el-radio-button v-for="item in prizeType" :label="item" :key=item />
 </el-radio-group>

const prizeType = ['特等奖','一等奖','二等奖','三等奖']
const prizeValue = ref<string>('特等奖')

// 改变抽奖类型
const changePrizeType = (type: string) => {
    
    
  prizeValue.value = type
  // 将按钮文字重置为开始
  showName.value = '开始'
  if(haveRemeber.value){
    
    
    // 校验当前奖项是否已经被抽完,第一次抽奖时候不校验
    const luckNameList = JSON.parse(localStorage.getItem('luckNameList')!)
    if(luckNameList && luckNameList.length){
    
    
      checkoutDraw(luckNameList)
    }
  }
}
  1. Namensrolle und Pause:
// 1. 洗牌算法:用于姓名每次循环前获得一个随机的姓名数组。主要目的是确保抽奖的公平性即每个人中奖的概率都相同
const shuffle = (arr: any) => {
    
    
  const arrNew = [];  // 打乱后的数组
  const len=arr.length 
  for (let i=len;i>0;i--){
    
    
    // 生成一个在0-len之间的随机数
    const rand=Math.floor(Math.random()*i)
    // 从原数组中拿出这个随机下标对应的数放入新数组当中
    arrNew.push(arr[rand]);
    // 从原数组当中删除拿出的这个值
    arr.splice(rand,1)
  }
  return arrNew;
}

// 2. 循环姓名列表,每次到最后一个姓名结束时,重新在循环一遍,如此往复。
const forNameList = (list: any) => {
    
    
  list = shuffle(list);
  for(let i=0; i<list.length; i++){
    
    
    setTimeout(() => {
    
    
      if(!isStop.value){
    
    
        showName.value = list[i].name;
        if(i == list.length - 1){
    
    
          // 当数组循环结束后,没有停止就在继续循环
          // 获取所有的姓名列表
          const allNameList = JSON.parse(localStorage.getItem('nameList')!)
          // 获取中奖人员姓名列表
          const luckNameList = JSON.parse(localStorage.getItem('luckNameList')!)
          if(luckNameList){
    
    
            // 将中奖人员从下一次抽奖中过滤掉,确保同一奖项每个人只能有一次中奖机会
            const newNameList = allNameList.filter((itemA: any) => luckNameList.every((itemB: any) => itemB.name !== itemA.name))
            // 将新的姓名列表重新赋值给 useNameList
            useNameList.value = newNameList
          }else{
    
    
            useNameList.value = allNameList
          }
          forNameList(useNameList.value)
        }
      }
    },50 * i);
  }
}

// 3. 开始抽奖与暂停
const drawStart = () => {
    
    
  // isStop.value ? startDraw() : stopDraw()
  const luckNameList = JSON.parse(localStorage.getItem('luckNameList')!)
  if(haveRemeber.value){
    
      // 如果没有参与人员不进行后续操作直接弹出导入人员提示
    if(luckNameList && luckNameList.length){
    
    
      // 校验当前奖项是否已经被抽完
      const flag = checkoutDraw(luckNameList)
      // 根据 startStatus 的状态决定当前奖项能否再抽
      if(flag){
    
    
        if(isStop.value){
    
    
          startDraw()
        }else{
    
    
          stopDraw()
        }
      }else{
    
      
        // 不可以抽奖,说明该奖项名额已经抽完了
        ElMessage.warning(`${
      
      prizeValue.value}` + '已经抽完了!')
      }  
    }else{
    
    
      //此时没有中奖人员,任何奖项下都可以抽奖
      if(isStop.value){
    
    
        startDraw()
      }else{
    
    
        stopDraw()
      }
    }
  }else{
    
    
    dialogVisible.value = true
  }
}

// 开始
const startDraw = () => {
    
    
  // 如果没有导入抽奖人员数据则提示 “请先导入抽奖人员数据!”
  if(!haveRemeber.value){
    
    
    dialogVisible.value = true
  }else{
    
    
    // 如果有数据开始循环滚动姓名,再次点击则停止滚动并弹出中奖人员
    isStop.value = false  // 开始循环  
    // 获取所有的姓名列表
    const allNameList = JSON.parse(localStorage.getItem('nameList')!)
    // 获取中奖人员
    const luckNameList = JSON.parse(localStorage.getItem('luckNameList')!)
    // 如果清除了中奖人员
    if(!luckNameList || luckNameList && !luckNameList.length){
    
    
      useNameList.value = allNameList
    }
    forNameList(useNameList.value)  // 循环姓名数组
  }     
}

// 暂停
const stopDraw = () => {
    
    
  isStop.value = true
  dialogVisible.value = true
  // 获取中奖人员数据弹窗显示,并存储起来
  const tableData = JSON.parse(localStorage.getItem('tableData')!)  // 所有数据
  let tableDrawData: any = JSON.parse(localStorage.getItem('luckNameList')!) || []
  tableData.forEach((item: any) => {
    
    
    if(item.name == showName.value){
    
    
      tableDrawData.push({
    
    
        name: item.name,
        sex: item.sex,
        dept: item.dept,
        prize: prizeValue.value
      })
    }
  })
  localStorage.setItem('luckNameList',JSON.stringify(tableDrawData))

  // 获取所有的姓名列表
  const allNameList = JSON.parse(localStorage.getItem('nameList')!)

  // 将中奖人员从下一次抽奖中过滤掉,确保每个人只能有一次中奖机会,也就是从 allNameList 中过滤掉 tableDrawData中的元素
  const newNameList = allNameList.filter((itemA: any) => tableDrawData.every((itemB: any) => itemB.name !== itemA.name))

  // 将新的姓名列表重新赋值给 useNameList
  useNameList.value = newNameList

  // 校验当前奖项是否已经被抽完
  checkoutDraw(tableDrawData)
}
  1. Überprüfen Sie, ob der aktuelle Gewinn gezogen wurde, initialisieren Sie ihn, wechseln Sie den Gewinntyp, klicken Sie auf die Lotterie und prüfen Sie, wann die Lotterie beendet ist
const checkoutDraw = (list: luckNameListType[]) => {
    
    
  // 此时表示有中奖人员,需要根据条件来确认是否可以在继续抽奖
  // 整理每一个奖项出现的次数
  let prizeList = list.map((item: luckNameListType) => item.prize)
  const prizObj =  prizeList.reduce((preValue: any, curValue: string)=>{
    
    
    preValue[curValue] = (preValue[curValue] + 1) || 1
    return preValue
  },{
    
    })
  console.log(prizObj,'prizObj==');

  // 如果此时在抽特等奖,只能有 1 个名额
  if(prizeValue.value === '特等奖'){
    
    
    if(prizObj['特等奖'] == 1) {
    
      // 此时特等奖不能在抽了
      startStatus.value = false 
    }else{
    
    
      startStatus.value = true 
    }
  }else if(prizeValue.value === '一等奖'){
    
      // 如果此时在抽一等奖,只能有 2 个名额
    if(prizObj['一等奖'] == 2 ){
    
      // 此时一等奖不能在抽了
      startStatus.value = false 
      } else{
    
    
      startStatus.value = true 
    }
  }else if(prizeValue.value === '二等奖'){
    
      // 如果此时在抽二等奖,只能有 5 个名额
    if(prizObj['二等奖'] == 5){
    
      // 此时二等奖不能在抽了
      startStatus.value = false 
      } else{
    
    
      startStatus.value = true 
    }
  }else if(prizeValue.value === '三等奖'){
    
      // 如果此时在抽三等奖,只能有 10 个名额
    if(prizObj['三等奖'] == 10){
    
      // 此时三等奖不能在抽了
      startStatus.value = false 
      } else{
    
    
      startStatus.value = true 
    }
  }
  return startStatus.value
}
  1. Neuziehung: Setzen Sie das Ergebnis der letzten Lotterie zurück. Sie können es bis zum Ende zurücksetzen. Nach dem Zurücksetzen sollte die Person, die gerade im Lotto gewonnen hat, weiterhin in der Liste der zu ziehenden Namen aufgeführt sein.
const drawAgain = () => {
    
    
  // 重新抽奖指的是清除最近一次抽奖记录,可以一直重置,直到抽奖记录为空。
  let tableDrawData = JSON.parse(localStorage.getItem('luckNameList')!)
  if(tableDrawData && tableDrawData.length){
    
    
    ElMessageBox.confirm(
      '确定要重置上一次的抽奖操作吗?',
      {
    
    
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }
    ).then(() => {
    
    
      const popValue = tableDrawData.pop()
      localStorage.setItem('luckNameList',JSON.stringify(tableDrawData))
      // 重置后刚才中奖的人应该继续放入待抽奖姓名列表中
      useNameList.value.push({
    
    
        name: popValue.name
      })
      ElMessage.success('重置成功!')
    }).catch(() => {
    
    
      ElMessage.info('取消重置!')
    })
  }else{
    
    
    ElMessage.warning('请先完成一次抽奖!')
  }
}
  1. Vorlage herunterladen: Sie können eine Vorlagendatei im Voraus vorbereiten. Ich stelle sie hier unter „Assets“ ein
import {
    
     saveAs } from 'file-saver'
const downTemplate = () => {
    
    
  const fileName = '参与抽奖人员模板.xlsx';  // 模板文件名
  const fileUrl = './src/assets/template/'  // 存放模板文件的路径(相对于index.html)
  saveAs(fileUrl + fileName, fileName)
}
  1. Daten importieren
<el-button v-show="drawTitle === '参与人员'" class="importData">
        导入数据
        <input class="inputFile" type="file" accept=".xls,.xlsx" @change="importData" />
</el-button>

import * as XLSX from 'xlsx'

const importData = (e: any) => {
    
    
  const file = e.target.files[0]   // 获取file对象
  const fileReader = new FileReader()  // 创建文件读取器
  fileReader.onload = (event) => {
    
    
    const result = event.target!.result  // 获取读取的结果
    const workBook = XLSX.read(result, {
    
    type: 'binary'})  // xlsx读取返回的结果
    const importData = XLSX.utils.sheet_to_json(
      workBook.Sheets[workBook.SheetNames[0]]
    )
    importData.forEach((item: any) => {
    
    
      tableDataTemp.value.push({
    
    
        name: item.姓名,
        sex: item.性别,
        dept: item.部门
      })
    });
    // 只存放姓名
    importData.forEach((item: any) => {
    
    
      tableNameData.value.push({
    
    
        name: item.姓名
      })
    });
    // 将导入的表格数据存到localStorage中
    localStorage.setItem('tableData', JSON.stringify(tableDataTemp.value))

    // 将姓名数据存在localStorage中
    localStorage.setItem('nameList', JSON.stringify(tableNameData.value))
    emits('nameList', tableNameData.value)
    // 给当前表格数据赋值
    tableData.value = tableDataTemp.value
    
    // 将导入的表格数据中的姓名存到pinia中
    appStore.getNameList(tableNameData.value)
  }
  fileReader.readAsBinaryString(file);
  // ((document.getElementsByClassName("inputFile")[0]).value = '')
}
  1. Daten löschen: Löschen Sie die Daten der Teilnehmer und Lotterieaufzeichnungen. Diese beiden sind unabhängig und beeinflussen sich nicht gegenseitig
const clearData = () => {
    
    
  ElMessageBox.confirm(
    '确定要清空所有数据吗?',
    {
    
    
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }
  ).then(() => {
    
    
    let empty: any = []
    tableData.value = []
    if(props.drawTitle === '参与人员'){
    
    
      localStorage.setItem('tableData', JSON.stringify(empty))
      localStorage.setItem('nameList', JSON.stringify(empty))
      emits('clearData','参与人员')
    }else{
    
    
      localStorage.setItem('luckNameList', JSON.stringify(empty))
      emits('clearData','抽奖记录')
    }
    ElMessage.success('清空成功!')
  }).catch(() => {
    
    
    ElMessage.info('取消清空!')
  })
}

5. Einige Beispieldiagramme

Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein

6. Hinweis

Der obige Code stellt nur einen Teil des Codes der aktuellen Funktion dar, sofern später Funktionserweiterungen oder -änderungen vorgenommen werden. Der obige Code kann entsprechend geändert werden. Wenn sich eine Änderung ergibt, wird er synchron geändert.

Je suppose que tu aimes

Origine blog.csdn.net/du_aitiantian/article/details/131766282
conseillé
Classement