作ることになったきっかけ
以前からLaravelのアウトプットとして何か作りたいと思っていたのですが、なかなかネタが思い浮かばずずっと先延ばしになっていました。 そんなある日、趣味の競馬観戦でレースの条件(開催月や距離、競馬場)が自分の記憶のものとかなり変わっていることが度々あり、自分の脳内番組表(競馬の開催スケジュールのこと)のアップデートが必要だと感じました。 そこでLaravelと、ついでにVue.jsも使ってクイズを作ることにしました。ざっくり仕様
- レースはGI、GⅡ、GⅢのようにグレードが定められているので、そのグレードごとにカテゴリー分けして、トップページで挑戦するカテゴリーを選択します。
- 問題は全10問。1つの画面で開催月、距離、競馬場を選択して解答します。
- 「回答する」ボタンをクリックすると、答えと解説が表示されます。
- 「次の問題へ」をクリックすると、次の問題が出題されます。
10問目まで解答が終わると、結果画面が表示されます。
出題〜解答までの動き
今回はシンプルに問題の出題のみ行うので、テーブルはproblemsテーブル1つのみです。 せっかくなら画面遷移のないSPAにしたいので、コンポーネントとしてトップページ、出題ページ、結果ページの3つのVueファイルを作成します。 簡単に処理の流れを書くと、 1. fetchItemで問題をテーブルからランダムに1件取得、開発ツールからのカンニングを防ぐため、idとレース名のみ取得。 2. fetchAnswerで該当の問題をidで検索、答え合わせをする。このとき、出題済みの問題がまた出題されないようにprocessed_flgをtrueにします。 3. fetchNewItemで次の問題を取得。ProblemCpntroller.php
public function index($category)
{
DB::table('problems')->update(['processed_flg' => false]);
$query = Problem::query();
$query->where('category', '=', $category);
$problem['count'] = $query->where('processed_flg', '=', false)->count();
if($query->exists()){
$query->select('id', 'title')->get();
$problem = $query->inRandomOrder()->first();
return $problem;
}
}
public function fetchNewItem(Request $request)
{
$category = $request->input('category');
$query = Problem::query();
$query->where('category', '=', $category);
$query->where('processed_flg', '=', false);
if($query->exists()){
$query->select('id', 'title')->get();
$problem = $query->inRandomOrder()->first();
return $problem;
}
}
public function fetchAnswer(Request $request)
{
$id = $request->input('id');
$problem = Problem::find($id);
$problem->processed_flg = true;
$problem->save();
return $problem;
}
Problem.vue
methods: {
async fetchItem() {
this.is_question = true
const response = await window.axios.get(`/api/ploblems/category/${this.category}`)
this.problem = response.data.title
this.is_answer = false
this.answer.id = response.data.id
},
async fetchNewItem() {
if(this.counter === 9) {
this.next_message = '結果発表'
} else if(this.counter === 10) {
this.$router.push({ name: 'result', params: { score: this.score } })
}
this.errors = {}
this.answer = {}
this.counter++
this.is_question = true
const response = await window.axios.get('/api/ploblems/category/', {params: {category: this.category}})
this.problem = response.data.title
this.is_answer = false
this.answer.id = response.data.id
},
async fetchAnswer() {
const answer = await window.axios.get('/api/ploblems/', {params: {id: this.answer.id}})
this.get_answer = answer.data
this.is_answer = true
this.is_question = false
if(this.answer.month !== this.get_answer.month) {
this.errors.month = true
}
if(this.answer.distance !== this.get_answer.distance) {
this.errors.distance = true
}
if(this.answer.place !== this.get_answer.place) {
this.errors.place = true
}
if(!this.errors.month && !this.errors.month && !this.errors.place) {
this.score++
}
}