美文网首页华南理工大学无线电爱好者协会软件小组
自己动手搭建业余无线电考(CRAC)试在线测试

自己动手搭建业余无线电考(CRAC)试在线测试

作者: 清洼 | 来源:发表于2018-09-10 23:55 被阅读7次

无线电频谱是大家共享的资源,在互联网没有将世界连接在一起之前,HAM们通过电波进行全球通信,是点对点最快的联通方式,但当时想建立起一个能与全球各地HAM进行联通的无线电系统是个非常复杂的工程;但伴随着PC进入千家万户,互联网又将大家连接在一起,在二十一世纪的今天,基于数字系统建立一个支持全球通信的短波系统已经不再是什么黑科技(前提是你已经学习了足够多的相关知识与技能)。因此即可以说是互联网击毁了HAM的空间,但同时也带给了HAM们一个新的世界。

全法操作无线电频谱,HAM需要首先考取无线电操作资格证,就如同开车上路之前需要先通过驾照考试获取驾驶资格证一样,只是这个证比较小重罢了。大家可以查看 中国业余无线电协会的相关规定,了解考试内容以及考试时间。

这里我们说一下其考试系统,我们可以通过官网上的链接下载其客户端,这个客户端功能还是可以的,但明显是上世界的古董级产物,应该不是用Delphi就是用vb编写的,你也就只能在windows电脑上使使,看看其下载页面的描述真心low呀。


业余无线电台操作技术能力验证考试程序ArExam(Amateur Radio Exam的缩写)由CRAC 根据国家规定的A类业余无线电台操作技术能力验证要求编制,目前有考试管理员版(CSM,Chinese-Simplified-Maneger)、高级管理版(CSS,Chinese-Simplified-Supervisor)和模拟考试版(CSB,Chinese-Simplified-Basic)三个版本,均可安装和选择导入不同类别的题库,三个程序版本所使用的题库文件格式相同。其中考试管理员版具有生成纸质试卷的功能,也可作为在电脑上进行机考的工具;高级管理版则具备某些特殊管理功能;模拟考试版本则只供学习用,两个版本抽取题目形成试卷的方法完全相同,但是模拟考试版不能生成纸面试卷,机上考试的显示方式与考试院管理版略有不同,在回答每道题目时都可以随时选择查看正确答案,仅供题库学习、熟悉机考操作界面和自我测试用。
程序运行环境为 Windows/XP。下载压缩文件包后先解压缩,再启动文件包中的安装程序“ArExamInstall.exe”,其余操作提示都很直观,对电脑稍微熟悉的人不难摸索掌握。
安装成功后桌面上会出现相应的快捷方式,点击即可进入模拟考试状态。进入运行后先选择“导入题库”,选择需要导入哪一类考试题库。答题前必须先键入姓名和18位身份证号码,并确认考试类别。
如果安装和运行过程中遇到病毒防护软件提示“未知软件”“存在危险”,则选择“信任”“放行”即可。


本文目标

让无线电考试的练习可以通过网页访问,这样我们就可以随时随地通过平板、手机、电脑进行复习及练习,让HAM们更好的为考试作准备。

2018-09-10 23-56-44屏幕截图.png

准备材料

  • 互联网连接的电脑一台
  • 一系列软件

软件清单

  • nodejs 使用其npm包管理下载其它依赖的内容,执行数据处理
  • angular 前端代码生成工具
  • gitGitHub将完成的成果放到互联供大家复习使用

操作步骤

  • 下载数据
  • 编写考试应用
  • 构建发布内容与上传发布

下载处理数据

我们首先需要通过官网页面获取业余无线电考试的题库。目前该文本的版为2017-1031-题库电子版v171031.zip
下载解压后目录中的文件内容如下:

A_分类题库(供公布用)(201710311221).txt
A_试卷涉及题号(v170717).txt
B_分类题库(供公布用)(201710311221).txt
B_试卷涉及题号(v170717).txt
C_分类题库(供公布用)(201710311221).txt
C_试卷涉及题号(v170717).txt
总题库文件(v171031).txt
总题库附图(v140331)

A,B,C三个分级别的题库,一个总题库和各级别涉及的总题库中的题号,另附有所题目的配图,官网上提供的软件应该也是基于这些文件的。因此这些已经是适宜于计算机系统理解与处理了。

万事开头难,我们就从A类考试介绍,后面的等级B,C可以留给大家去扩展(需要增加图片类的题目)。

我们可以看到官方对这个文件格式的解释

其中总题库文件包含了各类考试的所有题目。每道试题一般由六行文字组成:题目编号[I],问题[Q],答题选择[A]、[B]、[C]、[D],配套插图文件名[P]。总题库文件中每道题的正确答案选择总是[A]。当然在实际试卷中这些选择的次序会被随机颠倒。

查看一下A_分类题库(供公布用)(201710311221).txt的文件内容,

卷面题数:30
涉及题数:361

[I]LK0001
[Q]我国现行法律体系中专门针对无线电管理的最高法律文件及其立法机关是:
[A]中华人民共和国无线电管理条例,国务院和中央军委
[B]中华人民共和国无线电管理办法,工业和信息化部
[C]中华人民共和国电信条例,国务院
[D]中华人民共和国业余无线电台管理办法,工业和信息化部
[P]

[I]LK0002
[Q]我国现行法律体系中专门针对业余无线电台管理的最高法律文件及其立法机关是:
[A]业余无线电台管理办法,工业和信息化部
[B]个人业余无线电台管理暂行办法,国家体委和国家无委
[C]业余无线电台管理暂行规定,国家体委和国家无委
[D]中华人民共和国电信条例,国务院
[P]
... 此后省略很多行

对应说明可以看到 [I]为题库中的题号,[Q]为问题,[A],[B],[C],[D]为题目选项,[P]为题图中的配图。

为方便程序处理,首先我们需要修改这个文件,去掉前面综述性的卷面题目数量 ,涉及题数,使整个文件全是同构的题目内容(其实也可以在处理程序处跳过前面的几行,不过为了不增加程序额外的逻辑,咱们还是手动调整一下输入文件内容吧)。

为了便于前端页面使用,我们需要写一段处理程序,将修整后的文本文件转换为一个json格式的数据对象,这样使用javascript对其内容进行操作就十分方便了。json的内容结构如下。

{
  "A":[
  {"I":{"Q":"","A":"","B":"",...}},
  {Question}
   ...
]
}

我们使用Nodejs的javascript环境,其中有支持文件读写的API,我们读取整理过的A级题库文件dataA.txt',创建按行读取的对象objReadline,读取每行时(objReadline.on('line')通过switch判断当前状态,由于文件格式已经整理,当扫描到Q时创建一个问题对象,当扫描到I时将该题目放入问题库结果数组repo中,最后在流关闭时将处理好的repo内容字符串化之后写入到文件repoA.json中。


var fs = require("fs");
var readline = require('readline');


var fRead = fs.createReadStream('./dataA.txt');


var objReadline = readline.createInterface({  
    input: fRead});  
  
//var repo ={};  
var repo = [];
var question=null;
var idx;
var index = 1;  
objReadline.on('line', (line)=>{  
    var tmp = 'line' + index.toString() + ':' + line;  
    
    if(line!='')
    {
        switch(line.charAt(1))
        {
            case 'I':
                if(idx)
                {                    
                      repo.push(question);
                }
                idx = line.substr(3);
                break;
            case 'Q':                
                question={};//new question obj
                var q = line.substr(3);
                question["Q"] = q;                                                
                break;
            case 'A':
            case 'B':
            case 'C':
            case 'D':
                if(question.C==null)
                {
                    question.C=[];//make choice array
                }
                question.C.push(line.substr(3));
                break;
            case 'P':
                break;//ignore just now
            default:
                console.log('unkonw instruction '+ line)
                break;
        }
        
    }   
});  
  
objReadline.on('close', ()=>{  
    console.log('readline close...');
    let txtout = JSON.stringify(repo); 
    

    fs.writeFileSync('./repoA.json',txtout);
});  

至此我们得到了需要的问题库格式,下面我们创建将题库数据展示的工程。


编写考试应用

  1. 安装angular-cli
npm install -g @angular/cli

2.创建工程

ng new crac-test

3.定义问题类
新建问题类文件question.ts

export class Question{    
    Q:string;//问题
    C:string[];//答案选项
    A?:string;
    U?:string;
 }

Q是问题,C数组是重新排列顺序后的答案选项(A,B,C,D),A是正确答案,U是用户选择的答案。

  1. 准备题库数据类
    将上节数据转换中的结果repoA.json--> repoA.ts,并修改其中的内容,增加import { Question} from './question';另起一行加上export const QuestionRepoA:Question[] =,将转换的结果内容作为一个变量导出。

  2. 创建问题组件

ng generate component question

5.1 增加问题列表绑定

<div *ngFor="let i of filtered;let idx=index;">

  <h2 [class.wrong]="commited && (i.A!=i.U)"> {{idx+1}}.{{i.Q}}</h2>
  <ul>
    <li *ngFor="let c of i.C;"   
        [class.right]=" commited && c===i.A"
        [class.selected]=" c === i.U"
        (click)="checkAnswer(c,idx)"
    >
     {{c}}
    </li>
  </ul>

</div>

5.2 生成问题
首先导入上一步中导出的题库import { QuestionRepoA } from './repoA';

将题库内容作为问题题类一个成员questions = QuestionRepoA;,同时声明其它几个成员

  commited:boolean;
  done:number;
  score:number;
  total:number;
  
  constructor() {
    this.commited = false;
    this.done = 0;
    this.score = 0;
    this.total = 30;

   }

在构造函数中指定共考试30个题目;

  ngOnInit() {        
    while(this.filtered.length<this.total)
    {
      let idx =Math.floor(Math.random()*(this.questions.length+1));
      let item = this.questions[idx];
      item.A = item.C[0];//正确答案

      let newPos = Math.floor(Math.random()*4);//[0,1,2,3]
      item.C[0] = item.C[newPos];
      item.C[newPos] = item.A;

      //console.log(idx);
      this.filtered.push(this.questions[idx]);
    }
  }

在初始化函数中生成指定数量的题目,并随机从题库中抽取题目,并将正确选项A随机生成一个新位置(将两个位置中的内容交换,混淆选项),同时记录该题目的正确答案内容。
修改问题类关联的样式文件,区分选项的三个状态,正确,错误,选中。

.right {
    color:green;
}

.wrong {
    color:red;
}

li.selected {
    background-color: #BBD8DC !important;
    color: white;
}

通过条件结构指令(*ngIf)增加一块成绩标签(label)当用户提交之后显示成绩;

<div *ngIf="commited">
  <label class="score">
    {{score}}
  </label>
</div>
<div style="text-align:left; ">  
  <input type="button"  value="提交" (click)="commit()">
  <label>{{done}}/{{total}}</label>
</div>

增加提交按钮,当用户完成后点击提交,检查用户选择的情况,正确的显示绿色,错误的以红色显示答案选项,通过比较用户选择的答案 q.U 与q.A是否相同判断是否正确,通过比较当前项是否与用户选中一致判断是否为当前选中项;

[class.right]=" commited && c===i.A"
[class.selected]=" c === i.U"

checkAnswer检查当前完成情况,并更新题目的用户选项值

checkAnswer(answer:string,idx:number):void{
    if(this.filtered[idx].U == undefined)
      ++this.done;

    //console.log(`${idx}:${answer}`);
    this.filtered[idx].U = answer;  
  }```

用户点击提交时计算用户的分数
``` typescript
commit():void{
    this.score=0;
    for(let item in this.filtered)
    {        
      if(this.filtered[item].A === this.filtered[item].U)
        ++this.score;
    }

    this.commited = true;

  }

至此我们的在线考试开发部分已经完成。

构建发布内容与上传发布

构建发布内容

我们在开发模式下可以使用ng serve 来访问我们页面,但当我们需要发布时,还需要作构建发布的过程,这个过程相对前面步骤十分简单,通过执行下面命令完成。

ng build --prod --build-optimizer --base-href=/crac

注意通过base-href 修改根路径的位置,这点影响页面脚本,css的查找,如果 准备使用GitHub pages 则需要与发布步骤的GitHub工程名一致。

构建完成后,会在dist目录中生成下列文件:

3rdpartylicenses.txt  index.html  polyfills.js  styles.css
favicon.ico           main.js     runtime.js

在这个目录中执行如下命令新建一git代码仓库

git init
git add *
git commit -am "发布提交"

然后在github 上新建一个工程,根据提示将内容提交到仓库中

git remote add origin git@github.com:${yourUserName}/${youRepo}.git
git push -u origin master

其中${yourUserName}/${youRepo}替换为自己在github的用户名和代码仓库名字

发布页面,在SetttingsGitHub Pages面板下选择Source为主分支(master branch)点击保存(save)即可通过上方给出的链接访问自己发布的页面了,具体参见GitHub Pages帮助

结语

至此本节已经全部结束,大家可以直接使用在线例子进行考试练习,也可以下载代码改造,自己动手搭建自己的其它选择题考试的webApp帮助大家进行考试准备:-)。

相关文章

  • 自己动手搭建业余无线电考(CRAC)试在线测试

    无线电频谱是大家共享的资源,在互联网没有将世界连接在一起之前,HAM们通过电波进行全球通信,是点对点最快的联通方式...

  • 2019-01-11

    今天语文老师讲了试卷还考了试,数学也是讲了试卷考了试,社团课老师让我们自己动手做粮食粘画。音乐唱了粉刷匠,数鸭子

  • 关于辽宁省业余无线电考试-HKC小G-BH2QZL

    关于辽宁省业余无线电考试-HKC小G-BH2QZL 业余无线电的业余二字很关键,这表明其和专业以及商业有根本上的不...

  • 【对讲机的那点事】Olivia MFSK信号特征及信号分析

    业余无线电是一种以无线电通联为方式、以无线电研究为目的的个人业余爱好而不涉及谋取利益。由于短波频段可以利用电离层反...

  • 2020-02-23《民兵简易通信知识画册》

    W:\资料\ 【转】转自网易号@业余无线电

  • 环境搭建

    http://book.ecmoban.com/ ecshop在线手册 测试环境搭建: linux环境安装 架...

  • 测试环境搭建

    1.背景:记录下昨天搭建测试环境的步骤,实在是讨厌我们某某的嘴脸,不想求助他,自己动手丰衣足食,而且作为一名测试人...

  • 业余无线电活动

    上铝升降塔 夜以继日 人发烧,铁降温。 老当益壮

  • 正则表达式

    在线正则表达试测试链接 正则表达式测试链接网址 正则匹配 结果为 匹配目标分组匹配 结果为 贪婪模式匹配 .*匹配...

  • 自己动手搭建Nexus

    为什么要搭建私服 搭建Nexus私服的主要目的是为了解决工作上组件之间的jar包依赖管理。特别是基础架构部门的ja...

网友评论

    本文标题:自己动手搭建业余无线电考(CRAC)试在线测试

    本文链接:https://www.haomeiwen.com/subject/bbyrgftx.html