title: Ma Yuan Mao Gai Brushing Tool (WEB VERSION)
date: 2020-01-30 09:44:08
tags: [website, go, Vue.js]
categories: Development Record
photos: /img/banner/images/12.jpg
description: A brushing tool developed using Vue.js and Go
Before the exam, I quickly developed a brushing tool for Ma Yuan. After the exam, I had some time to expand it into a Ma Yuan Mao Gai brushing tool (https://github.com/jeasonlau/Question-test). I added features such as random brushing, exam simulation, and a question bank. However, to be honest, the command-line program in Python was not very user-friendly. Therefore, I decided to convert it into a web version. The project (https://github.com/jeasonlau/Question-test-web) has been open-sourced on GitHub. (I had no previous experience with front-end development, so there may be many shortcomings.)
Backend#
The backend uses the lightweight web framework Gin in Go. The code can be found here: (https://github.com/jeasonlau/Question-test-web/blob/master/back-end/main.go)!
It reads the "mayuan.json/maogai.json" files in the current directory and returns different results based on different routes:
Route | Result |
---|---|
/$subject/position/ | Returns the question at the specified position for the subject |
/$subject/random/ | Returns a random question for the subject |
/$subject/random/radio | Returns a random multiple-choice question for the subject |
/$subject/random/checkbox | Returns a random multiple-choice question for the subject |
Frontend#
The frontend uses Vue.js. When I was preparing to learn it, I found this sentence in the official documentation:
The official guide assumes intermediate knowledge of HTML, CSS, and JavaScript. If you are just starting to learn frontend development, using a framework as your first step may not be the best idea - master the basics first! Previous experience with other frameworks can be helpful, but it is not required.
Since I had no knowledge of frontend development, I first learned HTML basics and the first few sections of CSS on FreeCodeCamp. Then, I learned JavaScript up to the functions part on Liao Xuefeng's tutorial. After that, I started developing while referring to the official documentation.
First, I used the webpack scaffolding to create a Vue project and then installed and imported the Muse-UI component library.
-
Routing
import Vue from 'vue' import Router from 'vue-router' import index from '../components/index' import temp from '../components/temp' import exam from '../components/exam' import order from '../components/order' import about from '../components/about' Vue.use(Router) export default new Router({ routes: [ { path: '/', name: 'index', component: index }, { path: '/马原', name: 'mayuan', component: temp }, { path: '/毛概', name: 'maogai', component: temp }, { path: '/马原/顺序刷题', name: 'mayuanorder', component: order }, { path: '/毛概/顺序刷题', name: 'maogaiorder', component: order }, { path: '/马原/考试模拟', name: 'mayuanexam', component: exam }, { path: '/毛概/考试模拟', name: 'maogaiexam', component: exam }, { path: '/关于', name: 'about', component: about } ] })
-
Components
-
In
App.vue
, I wrote the common top bar, sidebar, and other content, and listened for route changes to modify the title. -
index.vue
andabout.vue
were written using pure HTML/CSS. -
temp.vue
is used to select the brushing method. -
order.vue
is the interface for sequential brushing, usingmu-pagination
for pagination.exam.vue
is the interface for exam simulation, usingmu-load-more
to load the question part. -
question.vue
is a unit question and is a child component oforder.vue
andexam.vue
. It listens for changes in thenum
prop, callsgetQuestion()
to load the corresponding question, and determines whether it is a multiple-choice or a multiple-selection question. TheifRight()
function is used to check if the answer is correct when selecting an option.// ifRight ifRight: function () { let answer if (this.isRadio === false) {// For multiple-selection questions, sort and join the answer array into a string answer = this.yourAnswer.sort().join("") } else {// For multiple-choice questions, directly get the answer answer = this.yourAnswer } if (answer === this.question["Answer"]) { this.isRight = true let that = this if (this.timer) clearTimeout(this.timer) this.timer = setTimeout(function () {// Display a notification for 2 seconds that.isRight = false }, 2000) } else { this.isRight = false } } // getQuestion getQuestion () { this.yourAnswer=[] // Get the request URL based on the parent component's path and the current num if (this.type === "/马原/顺序刷题") { this.url = "https://.../api/mayuan/position/" + (this.num - 1) } else if (this.type === "/毛概/顺序刷题") { this.url = "https://.../api/maogai/position/" + (this.num - 1) } else if (this.type === "/马原/考试模拟") { if (this.num <= 40) { this.url = "https://.../api/mayuan/random/radio" } else { this.url= "https://.../api/mayuan/random/checkbox" } } else if (this.type === "/毛概/考试模拟") { if (this.num <= 40) { this.url = "https://.../api/maogai/random/radio" } else { this.url = "https://.../api/maogai/random/checkbox" } } axios// Use axios to request the API and get the question .get(this.url) .then(response => { this.question = response.data if (this.question['Answer'].length > 1) {// Determine if it is a multiple-choice or a multiple-selection question this.isRadio = false } else { this.isRadio = true } }) }
-
Deployment#
I encountered several issues during deployment.
When I started debugging locally, I found that the questions were not being loaded. I checked the error messages in the Chrome console and found that it was because the backend did not have cross-origin resource sharing (CORS) configured. So I added the following line to the backend routes:
c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
The debugging worked fine, but after deploying to GitHub Pages, I found that the questions still couldn't be loaded. Checking the error messages, I learned that in an HTTPS webpage, HTTP resources cannot be loaded. So, the task became adding HTTPS to Gin.
After researching, I found that the general method is to apply for a subdomain and a free certificate. However, I didn't want to go through all that trouble, and I happened to have an HTTPS domain. So, I simply set up a reverse proxy in the current server block of Nginx:
location /api{
proxy_pass http://localhost:8080;
}
Then, I made requests to this address in GitHub Pages. However, I'm not sure if it was because of the intermediate Nginx, but I encountered another CORS issue. I couldn't find a solution immediately, so I had to deploy the frontend on Nginx as well to solve the problem (the only issue was that my server was not registered, so I had to manually enter the port to access it).