Python(Django)+Vue.js(Nuxt.js,Vuetify)を使ったシステムの開発です。
前回掲載したコードを説明します。
基本的にVue.jsの記述ですので、わかっている方は読み飛ばしてください。
.vueファイルは大きく3つのセクションからなります。
ファイルを分割することもできますが、一つにまとめることで見通しが良くなるのでこのまま使ったほうが理解しやすいと思います。
テンプレート部分
今回はVuetifyというマテリアルデザインフレームワークを導入しているためVuetifyの記述でテンプレートを作成します。
v-XXXX とあるタグの詳しい説明はVuetifyのUIコンポーネント解説を参照してください。
コードの後ろに //をつけたコメントで何をしているか記述しています。
<template>
<v-layout column justify-center align-center>
<v-flex col="12">
<v-row>
<v-col>
<h1><p class="text-center">見積もり</p></h1>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="8" lg="8" xl="8" pa-4> //←レスポンシブの設定
<div class="pl-4 pr-4 pt-4"> // ←pl=padding-left pr=padding-right pt=padding-top
<v-select
v-model="selected_cpu_id" // このセレクトボックスはselected_cpu_idと連動する。取得はgetメソッド、保存はsetメソッドが呼ばれる
item-text="name"
item-value="id"
:items=cpus
return-object
:clearable="true"
label="CPUを選ぶ">
</v-select>
</div>
<div class="pl-4 pr-4">
<v-select
v-model="selected_mother_board_id"
item-text="name"
item-value="id"
:items=mother_boards
return-object
:clearable="true"
label="マザーボードを選ぶ">
</v-select>
</div>
<div class="pl-4 pr-4">
<v-select
v-model="selected_video_card_id"
item-text="name"
item-value="id"
:items=video_cards
return-object
:clearable="true"
label="ビデオカードを選ぶ">
</v-select>
</div>
<div class="pl-4 pr-4">
<v-select
v-model="selected_storage_id"
item-text="name"
item-value="id"
:items=storages
return-object
:clearable="true"
label="ストレージを選ぶ">
</v-select>
</div>
<div class="pl-4 pr-4 pb-4">
<v-select
v-model="selected_pc_case_id"
item-text="name"
item-value="id"
:items=pc_cases
return-object
:clearable="true"
label="ケースを選ぶ">
</v-select>
</div>
</v-col>
<v-col ols="12" md="4" lg="4" xl="4" pa-4>
<v-card outlined>
<v-card-title align="center">見積り明細</v-card-title>
<v-card-text>
<v-row v-for="(item, ix) in selected" :key=ix> //←選択された商品を表示する
<v-col v-if="item.name != undefined" class="item-name col-8">{{item.name}}</v-col>
<v-col v-if="item.name != undefined" class="item-price col-4">{{item.price|japrice}}</v-col>
</v-row>
</v-card-text>
<div class="card-text col-12">
<v-divider></v-divider>
<div class="row">
<div class="item-name col-8">合計金額</div>
<div class="item-price col-4">{{all_price|japrice}}</div> //←合計金額を算出
</div>
<div class="row">
<div class="item-name col-8">消費税({{tax_rate}}%)</div>
<div class="item-price col-4">{{tax_price|japrice}}</div> //←消費税額を算出
</div>
</div>
<div class="card-text col-12">
<v-divider></v-divider>
<div class="row">
<div class="item-name col-8">お支払金額</div>
<div class="item-price col-4">{{total_price|japrice}}</div> //←お支払い総額を算出
</div>
</div>
<div class="card-text col-12" v-if="total_price > 0"> //トータル金額が0より大きかったら表示
<v-divider></v-divider>
<v-col class="text-center" cols="12">
<div class="my-2">
<v-btn large color="primary">購入</v-btn> //これは飾り
</div>
</v-col>
</div>
</v-card>
</v-col>
</v-row>
</v-flex>
</v-layout>
</template>
スクリプト部分
コードの後ろに //をつけたコメントで何をしているか記述しています。
<script>
import axios from "axios"
export default {
name: 'Shopping',
// フィルター
filters: {
japrice: function(str){ // ←日本円っぽい表示にするためのフィルター
if(isNaN(str)){
return ""
}else{
let num = parseInt(str, 10)
return '¥'+num.toLocaleString()
}
}
},
data: function() { //←ココから下は内部で保存するための変数
return {
tax_rate: 10,
// 取得DATA
cpus: [], //←DBから読み込んだCPUのオブジェクトが一時的に格納される
mother_boards: [], //←DBから読み込んだマザーボードのオブジェクトが一時的に格納される
video_cards: [], //←DBから読み込んだビデオカードのオブジェクトが一時的に格納される
storages: [], //←DBから読み込んだストレージのオブジェクトが一時的に格納される
pc_cases: [], //←DBから読み込んだケースのオブジェクトが一時的に格納される
// 選択ID
ids: {
cpu: Number, // ← セレクトボックスで選択したCPUのIDを保存する場所
mother_board: Number, // ← セレクトボックスで選択したマザーボードのIDを保存する場所
video_card: Number, // ← セレクトボックスで選択したビデオカードのIDを保存する場所
storage: Number, // ← セレクトボックスで選択したストレージのIDを保存する場所
pc_case: Number // ← セレクトボックスで選択したケースのIDを保存する場所
},
// 選択オブジェクト
selected: {
cpu: {}, //←セレクトボックスで選択したCPUのオブジェクトが格納される
mother_board: {}, //←セレクトボックスで選択したマザーボードのオブジェクトが格納される
video_card: {}, //←セレクトボックスで選択したビデオカードのオブジェクトが格納される
storage: {}, //←セレクトボックスで選択したストレージのオブジェクトが格納される
pc_case: {}, //←セレクトボックスで選択したケースのオブジェクトが格納される
}
}
},
created: function() {
// TODO: ここは1回で読み込めたほうがサーバの負荷が少ないので改良すること。
// CPU取得
let api = "http://127.0.0.1:8000/api/item/?category=1"
axios.get(api).then( //ココから下はAPIをコールし値を取得する。
function(response) {
this.cpus = response.data //←取得が成功したらcpuに取得した値をセットする
//console.log(this.cpus)
}.bind(this)
)
let api2 = "http://127.0.0.1:8000/api/item/?category=2"
axios.get(api2).then(
function(response) {
this.mother_boards = response.data
//console.log(this.mother_boards)
}.bind(this)
)
let api3 = "http://127.0.0.1:8000/api/item/?category=3"
axios.get(api3).then(
function(response) {
this.video_cards = response.data
//console.log(this.video_cards)
}.bind(this)
)
let api4 = "http://127.0.0.1:8000/api/item/?category=4"
axios.get(api4).then(
function(response) {
this.storages = response.data
//console.log(this.storages)
}.bind(this)
)
let api5 = "http://127.0.0.1:8000/api/item/?category=5"
axios.get(api5).then(
function(response) {
this.pc_cases = response.data
//console.log(this.pc_cases)
}.bind(this)
)
},
computed: {
//TODO: ここはほぼ同じ処理の繰り返しのため構造を検討すること
// 算出プロパティ
selected_cpu_id: { //テンプレートのセレクトボックスのv-modeと連携する。
get () { // v-modelが参照された場合に使われる
return this.ids.cpu
},
set (param) { // v-modelで値がセットされたときに使われる
if(param){
this.ids.cpu = param.id
this.selected.cpu = param
}else{
this.ids.cpu = ""
this.selected.cpu = {}
}
},
},
selected_mother_board_id: {
get () {
return this.ids.mother_board
},
set (param) {
if(param){
this.ids.mother_board = param.id
this.selected.mother_board = param
}else{
this.ids.mother_board = ""
this.selected.mother_board = {}
}
}
},
selected_video_card_id: {
get () {
return this.ids.video_card
},
set (param) {
if(param){
this.ids.video_card = param.id
this.selected.video_card = param
}else{
this.ids.video_card = ""
this.selected.video_card = {}
}
}
},
selected_storage_id: {
get () {
return this.ids.storage
},
set (param) {
if(param){
this.ids.storage = param.id
this.selected.storage = param
}else{
this.ids.storage = ""
this.selected.storage = {}
}
}
},
selected_pc_case_id: {
get () {
return this.ids.pc_case
},
set (param) {
if(param){
this.ids.pc_case = param.id
this.selected.pc_case = param
}else{
this.ids.pc_case = ""
this.selected.pc_case = {}
}
}
},
all_price: { //テンプレートの商品合計金額を取得する部分のコード
get () {
let total = this.calc_total()
return total
}
},
tax_price: { //テンプレートの消費税額を取得する部分のコード
get () {
let total = this.calc_total()
// 消費税計算
total = Math.floor(total * this.tax_rate / 100)
return total
}
},
total_price: { //テンプレートの総合計金額を取得する部分のコード
get () {
let total = this.calc_total()
// 消費税計算
let tax = Math.floor(total * this.tax_rate / 100)
// 税込トータル金額
return total + tax
}
}
},
methods: {
// 合計金額を算出
calc_total: function(){
let total = 0
if (typeof this.selected.cpu.price !== 'undefined') {
total = total + this.selected.cpu.price
}
if (typeof this.selected.mother_board.price !== 'undefined') {
total = total + this.selected.mother_board.price
}
if (typeof this.selected.video_card.price !== 'undefined') {
total = total + this.selected.video_card.price
}
if (typeof this.selected.storage.price !== 'undefined') {
total = total + this.selected.storage.price
}
if (typeof this.selected.pc_case.price !== 'undefined') {
total = total + this.selected.pc_case.price
}
return total
}
}
}
</script>
スタイル部分
<style> /* レシート内の商品名を左寄せにするところ */
.item-name{
text-align: left;
}
.item-price{ /* レシート内の金額を右寄せにするところ */
text-align: right;
}
</style>
こんな感じです。
コメント