下記の教本を参考に自動見積フォームを作りました。こちらです。興味のある方はチャレンジしてみてください。尚、フォームのデザインにはCSSフレームワークのBootstrapbootstrap@5.0.2を使用しています。
HTML
<div id=”app”>
<div class=”container bg-dark text-white p-5″>
<h2 class=”text-center border-bottom border-white pb-3 mb-5″>
自動見積フォーム
</h2>
<form>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″>制作したいムービ
<span class=”badge bg-danger”>必須</span>
</label>
<div class=”col-md-9″>
<div class=”row”>
<!– ムービーの種類 –>
<!– 余興ムービー –>
<div class=”col-md-5″>
<div class=”form-check form-check-inline”>
<input class=”form-check-input” type=”radio” name=”movie_type” id=”type1″ value=”余興ムービー” v-model=”movieType“>
<label class=”form-check-label” for=”type1″>余興ムービー</label>
</div>
</div>
<!– サプライズムービー –>
<div class=”col-md-5″>
<div class=”form-check form-check-inline”>
<input class=”form-check-input” type=”radio” name=”movie_type” id=”type2″ value=”サプライズムービー” v-model=”movieType“>
<label class=”form-check-label” for=”type2″>サプライズムービー</label>
</div>
</div>
<!– 生い立ちムービー –>
<div class=”col-md-5″>
<div class=”form-check form-check-inline”>
<input class=”form-check-input” type=”radio” name=”movie_type” id=”type3″ value=”生い立ちムービー” v-model=”movieType”>
<label class=”form-check-label” for=”type2″>生い立ちムービー</label>
</div>
</div>
<!– オープニングムービー –>
<div class=”col-md-5″>
<div class=”form-check form-check-inline”>
<input class=”form-check-input” type=”radio” name=”movie_type” id=”type4″ value=”オープニングムービー” v-model=”movieType“>
<label class=”form-check-label” for=”type3″>オープニングムービー</label>
</div>
</div>
</div><!–row–>
</div><!–class=”col-md-9–>
</div><!–form-group row–>
<!– 挙式日 –>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″ for=”wedding_date”>挙式日
<span class=”badge bg-danger”>必須</span>
</label>
<div class=”col-md-9″>
<input class=”form-control” type=”date” id=”wedding_date” placeholder=”日付をお選びください” v-model=”wedding_date“>
<small class=”form-text”>結婚式のお日にちを選択してください</small>
</div><!–col-md-9–>
</div><!–form-group row–>
<!–DVD仕上がり予定–>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″ for=”delivery_date”>DVD仕上がり予定日
<span class=”badge bg-danger”>必須</span>
</label>
<div class=”col-md-9″>
<input class=”form-control” type=”date” id=”delivery_date” v-bind:min=”tommorow” placeholder=”日付をお選びください” v-model=”delivery_date“>
<small class=”form-text”>挙式日の1週間前までにDVDが必要な場合が多いため、仕上がり予定を挙式日の1週間前に設定しております。</small>
</div><!–col-md-9–>
</div><!–form-group row–>
<!– 小計;基本料金 –>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″ >基本料金(税込)</label>
<div class=”col-md-9″>
<input type=”text” class=”form-control text-right” id=”sum_base” v-bind:value=” taxBasePrice | number_format” readonly>
</div><!–col-md-9–>
</div><!–form-group row–>
<!– オプションメニュー –>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″>オプションメニュー
<span class=”badge bg-info”>任意</span>
</label>
<!– BGM手配 –>
<div class=”col-md-9″>
<div class=”form-check mb-3″>
<input class=”form-check-input” type=”checkbox” id=”opt1″ v-model=”opt1_use”>
<label class=”form-check-label” for=”opt1″>BGM手配 + {{taxOpt1 | number_format }} 円</label>
<small class=”form-text”>当社で曲を手配する場合は、1曲あたり{{taxOpt1 | number_format }} 円(税込み)がかかります。</small>
</div>
<!– 撮影手配 –>
<div class=”form-check mb-3″>
<input class=”form-check-input” type=”checkbox” id=”opt2″ v-model=”opt2_use“>
<label class=”form-check-label” for=”opt2″>撮影 +{{taxOpt2 | number_format }} 円</label>
<small class=”form-text”>当社に撮影を依頼する場合の料金です(税込み)</small>
</div>
<!– DVF盤面印刷 –>
<div class=”form-check mb-3″>
<input class=”form-check-input” type=”checkbox” id=”opt3″ v-model=”opt3_use”>
<label class=”form-check-label” for=”opt3″>DVD盤面印刷 +{{taxOpt3 | number_format }} 円</label>
<small class=”form-text”>DVD盤面をデザインさせて頂き場合は、 円(税込み)がかかります。</small>
</div>
<!– 写真スキャニング –>
<div class=”form-row mb-3 align-items-center”>
<div class=”col-auto”>
<label class=”form-check-label” for=”opt4″ >写真スキャニング +{{taxOpt4 | number_format }}円</label>
</div>
<div class=”col-auto”>
<div class=”input-group”>
<input class=”form-control” type=”number” id=”opt4″ v-model.number=”opt4_num” min=”0″ max=”30″>
<div class=”input^group-append”>
<label class=”input-group-text” for=”opt4″>枚</label>
</div>
</div>
</div>
<small class=”form-text” >プリントアウトした写真のスキャニングをご希望の方は、1枚当たり{{taxOpt4 | number_format }}円にて承ります。</small>
</div><!–form-row mb-3 align-items-center–>
</div><!–col-md-9–>
</div><!–form-group row–>
<!– 小計、オプション料金 –>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″>オプション料金(税込)</label>
<div class=”col-md-9″>
<div class=”input-group”>
<input type=”text” class=”form-control text-right” id=”sum_opt” v-bind:value=”taxOptPrice | number_format” readonly>
<div class=”input-group-append”>
<label class=”input-group-text”>円</label>
</div>
</div><!–input-group–>
</div><!–col-md-9–>
</div><!–form-group row–>
<!– 合計:基本料金+オプション料金 –>
<div class=”form-group row”>
<label class=”col-md-3 col-form-label pt-0″>合計(税込)</label>
<div class=”col-md-9″>
<div class=”input-group”>
<input type=”text” class=”form-control text-right ” id=”sum_total” v-bind:value=”taxedTotalPrice | number_format” readonly>
<div class=”input-group-append”>
<label class=”input-group-text “>円</label>
</div>
</div><!–input-group–>
</div><!–col-md-9–>
</div><!–form-group row–>
</form>
</div><!–container–>
</div><!–app–>
Vue.js
Vue.filter(‘number_format’, function(val){ return val.toLocaleString(); }) | 数値を通貨書式「#,###,###」に変換するフィルター |
var app =new Vue({ el:’#app’, data:{ | |
taxrate:0.1, | 消費税率 |
movieType:’余興ムービー’, | 製作したいムービー |
basePrice: 30000, | 基本料金(税抜き) |
addPrice1:5000, addPrice2:10000, addPrice3:15000, addPrice4:20000, addPrice5:40000, addPrice6:45000, addPrice7:50000, | 割増料金 DVD仕上がり予定日が短納期の場合の割増料金 一か月未満:5,000円、3週間未満:10000円、2週間未満:15,000円、1週間未満:20,000円、3日後、40,000円、2日後:45,000円、翌日:50,000円 |
optPrice:0, | オプション料金 |
totalPrice:0, | 合計金額(税抜き) |
wedding_date:”, | 挙式日 |
delivery_date:”, | DVD仕上がり予定日 |
opt1_use:false, opt1_price: 5000, | オプション「BGM」 |
opt2_use:false, opt2_price:5000, | オプション「撮影」 |
opt3_use:false, opt3_price:5000, | オプション「DVD盤面印刷」 |
opt4_num:false, opt4_price:500, | オプション「写真スキャニング」 |
tommorow: null }, //data | 翌日の日付 |
methods:{ incTax: function(unTaxed){ return Math.floor(unTaxed * (1 + this.taxrate)); }, | 税抜き金額を税込みに変換するメソッド |
getDateDiff: function(dateString1, dateString2){ var date1 = new Date(dateString1); var date2 = new Date(dateString2) var msDiff = date1.getTime() – date2.getTime(); return Math.ceil(msDiff / (1000 * 60 * 60 * 24)); }, | 日付の差を求めるメソッド 日付を表す文字列から日付オブジェクトを生成 2つの日付の差分(ミリ秒)を計算 求めた差分を日付に変換 |
formatDate: function(dt){ var y = dt.getFullYear(); var m = (’00’ + (dt.getMonth()+ 1)).slice(-2); var d = (’00’+dt.getDate()).slice(-2); return (y + ‘-‘ + m + ‘-‘ + d); } },//methods | 日付をYYYY-MM-DDの書式で返すメソッド |
computed: { taxOpt1: function(){ return this.incTax(this.opt1_price); }, | オプション「BGM手配」の税込み金額を返す算出プロパティ |
taxOpt2: function(){ return this.incTax(this.opt2_price); }, | オプション「撮影」の税込み金額を返す算出プロパティ |
taxOpt3: function(){ return this.incTax(this.opt3_price); }, | オプション「DVD盤面印刷」の税込み金額を返す算出プロパティ |
taxOpt4: function(){ return this.incTax(this.opt4_price); }, | オプション「写真スキャニング」の税込み金額を返す算出プロパティ |
taxBasePrice: function(){ | 基本料金(税込み)を返す算出プロパティ |
var addPrice = 0; | 割増料金 |
var dateDiff = this.getDateDiff(this.delivery_date,(new Date()).toLocaleString()); | 納期までの残り日数を計算 |
if(21 <=dateDiff && dateDiff < 30){ addPrice = this.addPrice1; } | 割増料金を求める // 納期1ヶ月未満の場合 |
else if (14 <= dateDiff && dateDiff < 21){ addPrice = this.addPrice2; } | 納期3週間未満の場合 |
else if (7 <= dateDiff && dateDiff < 14){ addPrice = this.addPrice3; } | 納期2週間未満の場合 |
else if (3 <= dateDiff && dateDiff < 7){ addPrice = this.addPrice4; } | 納期1週間未満の場合 |
else if (dateDiff == 3){ addPrice = this.addPrice5; } | 納期が3日後の場合 |
else if (dateDiff == 2){ addPrice = this.addPrice6; } | 納期が2日後の場合 |
else if (dateDiff == 1){ addPrice = this.addPrice7; } | 納期が1日後の場合 |
return this.incTax(this.basePrice + addPrice); }, | 基本料金と割増料金を返す |
taxOptPrice: function(){ | オプション料金 |
var optPrice = 0; | 変数を設定 |
if(this.opt1_use) {optPrice += this.opt1_price;} | BGM手配 |
if(this.opt2_use) {optPrice += this.opt2_price;} | 撮影 |
if(this.opt3_use) {optPrice += this.opt3_price;} | DVD盤面印刷 |
if(this.opt4_num == ”) {this.opt4_num = 0;} optPrice += this.opt4_num * this.opt4_price; | 写真スキャニング |
return this.incTax(optPrice); }, // taxOptPrice | オプション料金(税込み)を返す |
taxedTotalPrice: function(){ return (this.taxBasePrice + this.taxOptPrice) } }, //computed | 合計金額(税込み)を返す算出プロパティ 基本料金とオプション料金の合計を返す |
created:function(){ | 挙式日には本日から数えて2か月後の日付を、DVD仕上がり予定日は挙式日の1週間前の日付をそれぞれ初期値として設定するため、createdライフサイクルハックを利用します。コンポーネントのインスタンスが生成し終わり、DOMと結びつく前に設定します。 |
var dt = new Date(); | 今日の日付を取得 |
dt.setMonth(dt.getMonth() + 2); | 挙式日に2か月後の日付を設定 |
this.wedding_date = this.formatDate(dt); | formatDateメソッドでyyyy-mm-ddの書式にする |
dt.setDate(dt.getDate() – 7); | DVD仕上がり予定日に、挙式日の1週間前の日付を設定 |
this.delivery_date = this.formatDate(dt); | formatDateメソッドでyyyy-mm-ddの書式にする |
dt = new Date(); dt.setDate(dt.getDate() + 1); this.tommorow = this.formatDate(dt) } //created | DVD仕上がり予定日に翌日以降しか入力できないようにする |
}) //app |
この本を参考に学び、完成させることができました。しかし、プログラミング初心者の私が詳しく解説することは、おこがましく、難しく出来ません(ToT) その点、この本では丁寧な解説が載っていますので、解説とともにコードを書き、完成させればより深く学ぶことができます(^.^) 身に付けて消えないスキルがこの値段。買っておいてよかったです。