基于html和vue的随机点名器

随机点名器是一个简单而高效的点名工具,为教师、辅导员和团队组织者提供了一种快速、方便的方式来随机点名、抽选人员。本文将介绍随机点名器的程序优势以及详细的使用方法,帮助您在教育、培训和团队活动中更好地应用。

    1.程序优势:

随机点名器具有以下几个优势,使其成为您点名工具的首选:

1.1 简单易用:随机点名器采用了直观的用户界面和直观的操作流程,使您能够快速上手,无需复杂的设置和配置。只需几个简单的步骤,您就可以导入名单、设置抽选人数,并开始点名。

1.2 多种名单导入方式:随机点名器支持多种名单导入方式,包括文本文件(.txt、.csv)和电子表格文件(.xlsx)。无论您的名单是以文本格式还是电子表格格式存储,都可以轻松导入到随机点名器中进行使用。

1.3 灵活抽选设置:随机点名器提供了灵活的抽选设置,您可以根据需要设置抽选人数,从名单中随机抽选指定数量的人员。这使得随机点名器不仅适用于传统的点名场景,还适用于分组、抽奖等需要随机选择人员的情况。

       2.使用方法:

下面是使用随机点名器的简单步骤:

2.1 导入名单:打开随机点名器,点击“导入名单”按钮,选择您要导入的名单文件。随机点名器支持文本文件(.txt、.csv)和电子表格文件(.xlsx)格式。

2.2 预览名单:在名单导入成功后,随机点名器将显示一个预览列表,展示导入的名单内容。您可以查看名单内容,确保导入正确无误。

2.3 设置抽选人数:在随机点名器界面上,您可以设置要抽选的人数。只需输入要抽选的人数,随机点名器将从名单中随机抽选出指定数量的人员。

2.4 开始抽选:点击“开始抽选”按钮,随机点名器将开始抽选人员,并展示抽选结果。您可以在结果区域中查看抽选到的人员,以完成点名或其他用途。

      3.总结:

随机点名器是一个简单而高效的点名工具,为教育、培训和团队活动带来了便利。通过其简单易用的操作界面和多种名单导入方式,您可以轻松导入名单、设置抽选人数,并快速进行随机抽选。不仅适用于传统的点名场景,还可以应用于分组、抽奖等各种需要随机选择人员的场合。

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>随机点名器</title>
  <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
  <style>
    #app {
      max-width: 600px;
      margin: 0 auto;
      padding: 20px;
    }

    .name-list {
      margin-bottom: 10px;
    }

    .name-list .el-button {
      margin-right: 10px;
    }

    .name-list .el-dialog__footer {
      padding: 10px 20px;
      text-align: right;
    }

    .result-area {
      margin-top: 20px;
      padding: 10px;
      border: 1px solid #ccc;
      font-size: 24px;
      text-align: center;
      min-height: 100px;
    }

    @media (max-width: 600px) {
      #app {
        padding: 10px;
      }

      .name-list .el-button {
        margin-bottom: 10px;
      }
    }
  </style>
</head>

<body>
  <div id="app">
    <h1>随机点名器</h1>
    <el-button type="primary" @click="startPick" :disabled="picking || selectedCount <= 0 || nameList.length === 0">
      开始抽选
    </el-button>
    <el-input-number v-model="selectedCount" :min="1" :max="nameList.length" :disabled="picking"></el-input-number>
    <div class="name-list">
      <el-button type="text" @click="showNameListDialog">名单管理</el-button>
      <el-button type="text" @click="importNameList">导入名单</el-button>
      <el-button type="text" @click="exportNameList" :disabled="nameList.length === 0">导出名单</el-button>
      <el-button type="text" @click="clearNameList" :disabled="picking || nameList.length === 0">清空名单</el-button>
    </div>

    <el-dialog title="名单管理" :visible.sync="nameListDialogVisible" width="400px">
      <el-table :data="nameList" empty-text="名单为空" @edit="editName" @remove="removeName">
        <el-table-column prop="name" label="姓名"></el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-button size="mini" @click="editName(scope.$index, scope.row)">编辑</el-button>
            <el-button size="mini" @click="removeName(scope.$index)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>

      <div slot="footer" class="dialog-footer">
        <el-input v-model.trim="newName" placeholder="请输入姓名"></el-input>
        <el-button @click="addName" :disabled="newName.trim() === ''">添加</el-button>
        <el-button @click="closeNameListDialog">关闭</el-button>
      </div>
    </el-dialog>

    <div v-if="!picking" class="result-area">
      <div v-if="results.length === 1" class="result">{{ results[0] }}</div>
      <div v-else>
        <div v-for="result in results" class="result" :key="result">{{ result }}</div>
      </div>
    </div>
    <div v-else>
      <div class="result">{{ results[0] }}</div>
    </div>

    <el-dialog title="名单预览" :visible.sync="previewDialogVisible" width="400px">
      <el-table :data="previewNameList" empty-text="名单为空">
        <el-table-column prop="name" label="姓名"></el-table-column>
      </el-table>

      <div slot="footer" class="dialog-footer">
        <el-button @click="confirmImportNameList">确定导入</el-button>
        <el-button @click="cancelImportNameList">取消</el-button>
      </div>
    </el-dialog>
  </div>

  <script src="https://lib.baomitu.com/vue/2.7.7/vue.js"></script>
  <script src="https://unpkg.com/element-ui/lib/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js"></script>

  <script src="https://cdn.jsdelivr.net/npm/xlsx/dist/xlsx.full.min.js"></script>

  <script>
    new Vue({
      el: '#app',
      data() {
        return {
          nameList: [],
          newName: '',
          nameListDialogVisible: false,
          selectedCount: 1,
		  progress: 0,
          picking: false,
          results: [],
          speechQueue: [],
          speechTimer: null,
          importedNameList: [],
          previewNameList: [],
          previewDialogVisible: false
        };
      },
      methods: {
        showNameListDialog() {
          this.nameListDialogVisible = true;
        },
        closeNameListDialog() {
          this.nameListDialogVisible = false;
        },
        addName() {
          if (this.newName.trim() !== '') {
            this.nameList.push({ name: this.newName.trim() });
            this.newName = '';
          }
        },
        editName(index, row) {
          const newName = prompt('请输入新的姓名', row.name);
          if (newName !== null) {
            this.$set(this.nameList, index, { name: newName.trim() });
          }
        },
        removeName(index) {
          this.nameList.splice(index, 1);
        },
        startPick() {
          if (this.nameList.length > 0 && this.selectedCount <= this.nameList.length) {
            this.picking = true;
            this.results = [];
            this.speechQueue = [];
			this.stopSpeak();  // 停止之前的朗读

            const selectedNames = [];
            while (selectedNames.length < this.selectedCount) {
              const randomIndex = Math.floor(Math.random() * this.nameList.length);
              const selectedName = this.nameList[randomIndex].name;

              if (!selectedNames.includes(selectedName)) {
                selectedNames.push(selectedName);
              }
            }

this.results = selectedNames;
this.currentSpeechNames = selectedNames;  // 更新当前朗读的名单
this.enqueueSpeechNames(selectedNames);
this.speakNames();
this.picking = false;

          }
        },
        enqueueSpeechNames(names) {
          this.speechQueue = this.speechQueue.concat(names);
        },
        speakNames() {
          this.speakNextName();
          this.speechTimer = setInterval(() => {
            this.speakNextName();
          }, 1200);
        },
        speakNextName() {
          if (this.speechQueue.length > 0) {
            const name = this.speechQueue.shift();
            this.speak(name);
          } else {
            clearInterval(this.speechTimer);
          }
        },
        speak(name) {
          const utterance = new SpeechSynthesisUtterance(name);
          utterance.lang = 'zh-CN';
          utterance.pitch = 1.2;
          speechSynthesis.speak(utterance);
        },
        stopSpeak() {
          speechSynthesis.cancel();
          clearInterval(this.speechTimer);
        },
        importNameList() {
          const fileInput = document.createElement('input');
          fileInput.type = 'file';
          fileInput.accept = '.txt, .csv, .xlsx, .xls';
        
          fileInput.onchange = (event) => {
            const file = event.target.files[0];
            const ext = file.name.split('.').pop().toLowerCase();
        
            if (ext === 'txt' || ext === 'csv') {
              const reader = new FileReader();
              reader.onload = (e) => {
                const content = e.target.result;
                // 处理文本文件内容
                this.handleTextFile(content);
              };
              reader.readAsText(file);
            } else if (ext === 'xlsx' || ext === 'xls') {
              const reader = new FileReader();
              reader.onload = (e) => {
                const data = new Uint8Array(e.target.result);
                const workbook = XLSX.read(data, { type: 'array' });
                const sheetName = workbook.SheetNames[0];
                const worksheet = workbook.Sheets[sheetName];
                const nameList = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
        
                this.previewNameList = nameList.map((name) => ({ name }));
                this.importedNameList = nameList.map((name) => ({ name }));
                this.previewDialogVisible = true;
              };
              reader.readAsArrayBuffer(file);
            } else {
              alert('您导入的文件不受支持,请导入后缀为 .txt/.csv/.xlsx/.xls 的文件');
            }
          };
        
          fileInput.click();
        },
        handleTextFile(content) {
          // 处理文本文件内容
          const nameList = content.split('\n')
            .filter((name) => name.trim() !== '')
            .map((name) => ({ name: name.trim() }));
        
          this.previewNameList = nameList;
          this.importedNameList = nameList;
          this.previewDialogVisible = true;
        },

confirmImportNameList() {
  this.nameList = [...this.importedNameList];
  this.importedNameList = [];
  this.previewNameList = [];
  this.previewDialogVisible = false;
},

        cancelImportNameList() {
          this.importedNameList = [];
          this.previewNameList = [];
          this.previewDialogVisible = false;
        },
        clearNameList() {
          this.nameList = [];
        },
        exportNameList() {
          const data = this.nameList.map((item) => [item.name]);
          const worksheet = XLSX.utils.aoa_to_sheet(data);
          const workbook = XLSX.utils.book_new();
          XLSX.utils.book_append_sheet(workbook, worksheet, '名单');
          XLSX.writeFile(workbook, 'name_list.xlsx');
        }
      }
    });
  </script>
</body>

</html>

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值